Generally speaking removing systems is something i wouldn’t be doing based on level load. The presence of components drives whether or not a system runs.
This should work correctly though. We’ll take a look at this exception.
What is very unclear to me in ECS is how to handle things like for example level settings and how to pass them to the systems. You know, all the “singleton” objects.
I have implemented a factory class that creates the systems and injects (through the contructor) dependencies like level settings to them. But naturally such a system should live only through the level and no longer, that is why I am trying to destroy it. (Well, on second thought this probably isn’t the correct way.)
The other way could be to have an entity with the LevelSettings component, but it means writing much more code than what I was used to:
[Zenject.Inject] LevelSetting levelSettings;
In your TwoStickShooter example you use a static class for settings, but static class is not probably something you would like to use in a real game.
So how would you “inject” things like level settings to the system in some scalable and maintenable way?
I wouldn’t say my answer is the best approach, but I would simply have system class, with static properties, of which you assign relevant values, when level is started/restarted/ended.
I’ve talked about this before and wrote a solution to allow custom injections (I use Zenject): Request for World.AddManager
I really wish they’d just add an the AddManager method themselves to World so we can control how to instantiate systems however we want without having to hack at it.
Yes, I am using similar approach, but now I am not sure about it. As I wrote above, with constructor injection I would need to create/destroy systems with level loading and it doesn’t seem too effective.
Well, I will probably do so. I generally like the idea of ECS to “let the systems pick what they need”, it is just that for such a simple (single) things it feels like a hack.
Problem is still here in 21 preview. Deleting a system causes an exception in the next player loop update, when this system is accessed from the native. System is disposed but looks like native had not cleared an update hook registration for it. Player loop updates correctly inside the ScriptBehaviourUpdateOrder.UpdatePlayerLoop(world);.
I had a similar problem when destroying a world during the PlayerLoop resuling in some systems still getting updates for the current frame. My workaround for this was to set all the systems to Enabled=false before deleting the world.
As of earlier this year, systems are no longer added directly to the player loop; instead, they’re part of the ComponentSystemGroup hierarchy. If you really want to destroy an individual system at runtime (and I agree with Joachim that this should not be a common use case ), the component system group hierarchy will continue to attempt to update it, and you’ll get an exception about the system already being deleted. The next release of the Entities package (preview33) will include the necessary function, ComponentSystemGroup.RemoveSystemFromUpdateList(), which (unsurprisingly) removes the specified system from the group & prevents it from participating in further updates. The system can then be safely destroyed.
But how do I do this?
I’m writing a plugin that support both entities and gameobjects and I’m creating the system in a way that its easy to use and works similar to the gameobjects. Under the hood it does ecs stuff so for example settings are added outside the ecs componensystem component.
World.GetOrCreateSystem will give you a reference.
For example, you could use initializationSystemGroup = World.GetOrCreateSystem<InitializationSystemGroup>(); in the OnCreate method, and then call initializationSystemGroup.RemoveSystemFromUpdateList(systemToBeDestroyed); and then World.DestroySystem(systemToBeDestroyed);