Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested contexts #3

Closed
MaximumViciousDeer opened this issue Apr 1, 2015 · 5 comments
Closed

Nested contexts #3

MaximumViciousDeer opened this issue Apr 1, 2015 · 5 comments
Labels

Comments

@MaximumViciousDeer
Copy link

I am making spaceship game which currently doesn't use DI, but have read about this framework and would like to use it. Some basic info about my game:

  • Each player has one ship.
  • Ships can be docked inside bigger ships.
  • Local co-op support.

I was thinking about making each ship a context - that way I could inject ship configuration, player input etc. to the ship's submodules (which are sub transforms of the ship). The ship may be nested when docked.
This does however not seem to be entirely achievable using ADIC.
How would you use ADIC in this case?

@intentor
Copy link
Owner

intentor commented Apr 1, 2015

That kind of scenario is something that DI can help a lot!

Considering that "context" in Adic could be translated to a container (an instance of InjectionContainer, created inside the SetupContainers() method of a GameRoot) you could have a specific container for each of your ships. However, I don't think this would be the best approach.

You could place specific configurations of your ships in the same container using different conditional identifiers (see Conditions) and also bind any common configurations or objects that are shared among all ships in that same container. So, in your modules (MonoBehaviours or not), you inject the configurations using these identifiers.

I don't know exactly what happen when the ship is docked (whether e.g. the "mothership" will then be controlled by the player). But, if that's the case, or even to ensure some communication between the ship and the (for the lack of a better word) "mothership", you could dispatch a command (see Using commands) to pass the control to the "mothership" by configuring the necessary modules (and also to dock the ship).

I hope that can help!

@MaximumViciousDeer
Copy link
Author

Thanks for the info! I missed the parentInstance field of the context in the conditions section when reading earlier. Using that instance I could do something like:

//Players created before container setup
foreach (var player in players)
{
    int playerID = player.ID;
    PlayerInput input = player.Input;

    container.Bind<PlayerInput>().ToGameObject(input).When(c => 
        ((MonoBehaviour)c.parentInstance)
        .transform
        .root
        .GetComponent<Ship>()
        .Player
        .ID == playerID
    );
}

Which would inject the input object for all modules of a ship.

I also guess it would work for players joining mid-game if I just create all players (in the above foreach) beforehand - since it is not possible to update the container after the initial SetupContainers()?

Is it possible to redo injection at a later stage (long after object creation)? Say I create a ship module at start and later on it changes owner, could I redo the injection to get a new player input instance? Perhaps by doing this.Inject()?

@intentor
Copy link
Owner

intentor commented Apr 1, 2015

That should do the trick if new instances of the Player component have the correct IDs (and the player list contains the unique inputs for each player), and should also work when a new player joins mid-game.

It's a complex binding, but looks like an acceptable approach that Adic can handle just fine.

However, I don't feel this approach is the best for your problem. Why not use a factory to decide which input object to use based on the same conditions (a factory receives the same InjectionContext object as the condition)? The main use of a factory is to customize the way an object is created.

Analyzing your code, looks like the Input is a MonoBehaviour. Have you thought about making it a regular class? This way it doesn't need to be attached to any game object and new instances could be created directly by the container itself.

Obviously I don't know how your code is organized, so I can't really say that it could be a proper solution.

And, although not recommended, you could add bindings to a container after SetupContainers() by either holding a reference to it or by injecting the container through an IInjectionContainer constructor parameter or class field - but that not necessarily will help you on solving the input problem described above.

@intentor intentor closed this as completed Apr 1, 2015
@intentor intentor reopened this Apr 1, 2015
@intentor
Copy link
Owner

intentor commented Apr 1, 2015

To make the use of factories more pleasurable, I opened the issue #4 to allow them to be created by the container, so they can have any dependencies resolved (currently factories don't support injection, so you could not e.g. receive the container as a dependency to resolve other types when manually creating an object).

@MaximumViciousDeer
Copy link
Author

Thanks, very good suggestions! #4 seems like a smart way of handling this, I'll try the factory approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants