How to use MonoBehaviourInstaller #52
-
Lets say I have many duplicated objects in scene with the same component like enemies, loot etc. I've created separate MonoInstallers for them like EnemyInstaller and LootInstaller. Zenject have GameObjectContext to register such installers inside gameobject level containers. I suppose I need to use MonoBehaviorSubordinateEntryPoint to make similar thing?
then inside scene context I need to find all objects on scene with GameObjectEntryPoint and pass scene container with MonoInstaller like this? var gameObjectEntryPoints = FindObjectsByType<GameObjectEntryPoint>();
foreach (var gameObjectEntryPoint in gameObjectEntryPoints )
{
var data = gameObjectEntryPoint.gameObject.GetComponent<MonoBehaviourInstaller>();
gameObjectEntryPoint.Initiate(data);
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Starting from the beggining
For instance public class MainMenuEntryPoint : MonoBehaviorSubordinateEntryPoint
{
public SomeReusableWidgetInstaller someReusableWidgetInstaller; //Serialize and reference the other installer
public override void Install(DiContainerBindings b)
{
someReusableWidgetInstaller.Install(b)
}
}
public class SomeReusableWidgetInstaller : MonoBehaviourInstaller
{
public ... // references here
public override void Install(DiContainerBindings b)
{
b.Bind...
//Complicated reusable or encapsulated system
}
} When dealing with objects that have different lifetimes / are created dynamically you can use MonoBehaviorSubordinateEntryPoint so that each one of those objects is created and initialized on it's own at runtime. thus when creating an object you would probably do something like this public class EnemyData
{
//Add properties here if the enemy has some dynamic values provided to it
//Add parent IDiContainer here if the enemy needs to have the parent
//Alternatively instead of adding the parent DiContainer, the exact dependencies needed from the parent can be resolved and provided directly to the enemy
}
public class EnemyEntryPoint : MonoBehaviorSubordinateEntryPoint<EnemyData, Enemy>
{
public Enemy enemy; //Serialize and reference enemy stuff here
public override void Install(DiContainerBindings b)
{
b.Bind<Enemy>().Default().FromInstance(enemy);
//Other complicated enemy binding logic here
}
} Thus creating enemies at runtime using the container could be done like this public EnemyEntryPoint enemyEntryPoint ;
public Enemy CreateEnemy()
{
var enemyEntryPoint = GameObject.Instantiate(enemyEntryPoint );
return enemyEntryPoint.Initiate(new EnemyData());
} If those objects are already in the scene, you could also do public EnemyEntryPoint[] enemyEntryPoints ;
public Enemy[] InitializeEnemies()
{
return enemyEntryPoints .Select(x => x.Initiate(new EnemyData()).ToArra();
} Having said all of that there are also other options in case the enemies are but simple single class systems. In that case, you could have for example a simple enemies installer that references those enemies and just bind the enemy classes using non lazy so that enemies are injected and initialized using the subordinate container of the scene and not one for it's own public class EnemiesInstaller : MonoBehaviourInstaller
{
public Enemy[] enemy; //Serialize and reference enemies
public override void Install(DiContainerBindings b)
{
foreach(var enemy in enemies)
{
b.Bind<Enemy>().Default().FromInstance(enemy).NonLazy();
}
}
} Even another option if enemy classes are not very simple classes but have some more meat, would be to use FromSubContainerResolve In this example below, instead of having a single installer for all enemies, each enemy can have it's own installer and create the hidden container we talked in a previous question. public class EnemyInstaller : MonoBehaviourInstaller
{
public Enemy enemy; //Serialize and reference enemies
public override void Install(DiContainerBindings b)
{
b.Bind<Enemy>().Default().FromInstance(enemy);
//Other enemy stuff
}
}
public class GameplayEntryPoint : MonoBehaviorSubordinateEntryPoint
{
public EnemyInstaller[] enemyInstallesr; //Serialize and reference the other installer
public override void Install(DiContainerBindings b)
{
foreach(var enemyInstaller in enemyInstallers)
{
b.Bind<Enemy>().FromSubContainerResolve(enemyInstaller).NonLazy();
}
}
} Remember that you will need to add NonLazy to the bindings that you want to have "activated" if those are not resolved anywhere. Also notice that you can bind the same thing more than once to the container. If you called Resolve on that type it will return the first one, ResolveAll would return all of them. There are really many ways to do it and it all depends on how you want to structure your application and how you plan to grow it. IMO if the enemies are static and have somewhat complex systems internally would personally take the last one using FromSubContainerResolve. Hopfully this is helpful to you. |
Beta Was this translation helpful? Give feedback.
Starting from the beggining
MonobehaviourInstaller
are meant to encapsulate part of the bindings they cannot be started directly, instead they must end up being called by some entry pointsFor instance