Search Unity

Problem to reset a game.

Discussion in 'Entity Component System' started by daserra, Sep 13, 2018.

  1. daserra

    daserra

    Joined:
    Dec 7, 2016
    Posts:
    14
    Hello people.

    I'm using a Hybrid ECS system, so, for a few Systems i'm keeping some static variables that i will consume during the game.

    Like this
    Code (csharp):
    1.  
    2. public struct Data {
    3. readonly public int Length;
    4. public ComponentDataArray<Enemy> Enemy;
    5. }
    6.  
    7. [Inject] private Data data;
    8.  
    9. public static Dictionary<int, ParteDoLevel> ptsLevel = new Dictionary<int, ParteDoLevel> ();
    10.  
    As you can see my ptsLevel is static and is populated at some point during the game. And when player die I clean up all entities using this code above then i load the mainmenu scene.
    Code (csharp):
    1.  
    2. var entityManager = World.Active.GetOrCreateManager<EntityManager> ();
    3. var entityArray = entityManager.GetAllEntities ();
    4. foreach (var e in entityArray)
    5. entityManager.DestroyEntity (e);
    6. entityArray.Dispose ();
    7.  
    8. SceneManager.LoadSceneAsync ("MainMenu");
    9.  
    The problem is when i load the game scene again, that static variable still populated. There is some way to reset a system static variables?

    I tried this code above but i got tons of errors.
    Code (csharp):
    1.  
    2. World.DisposeAllWorlds();
    3. World world = new World("World");
    4. World.Active = world;
    5.  
     
  2. NearAutomata

    NearAutomata

    Joined:
    May 23, 2018
    Posts:
    51
    Try not to use static variables and make them local and inject the corresponding system. @5argon might have more inside on that topic.
     
    daserra likes this.
  3. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    The `static` is very evil in the system context because system is supposed to be modular by design. I lose at least 4 days reverting the `static` design so I recommended you should not use it. Static only reset on script recompilation. The point of not having the static is precisely that the static is hard to clean up. Not even destroying a world can get rid of static. And then if you make a 2nd world some time in the future both worlds will share the same static, but I bet the meaning of your static field is intended to only one world. Also when you run a unit test the static variable does not reset in-between tests. That's a big step back.

    You get a tons of error when destroying worlds because it destroys all the running systems along with it. Player loop will then run a lots of null reference (so you must also update the player loop). Static variable resides on a level higher than worlds (heap) so there's no way to mass destroy them like that. But I doubt your intention is to destroy all the system logic and just want to clean up the data, so destroying the world is not a correct answer. Mass entity clean up that you did is the correct approach, but it does not clean the static state. So :

    A. Make the static into a private variable with public accessor and when you do want it, use EntityManager.GetExistingManager<SystemName>().Accessor. You see this API is still static-based, but it bridges into non-static world. This is much better because "existing" manager will ensure that that is the only one (static's important property) in the world. You still need to clean up the private variable manually since it is technically out of entity system. When I do this I put ResetState() method on the system that can reset its private variables then : EntityManager.GetExistingManager<SystemName>().ResetState()

    B. Or even better but more involving/annoying to set up you can use "system state component data" (learn it in the docs I think they have added it now). This way it is now "official" that the data belongs to the system but at the same time conforms to entity design. Change the accessor mentioned in A. to a public method that grabs the entity from ECS and present it to outside world. When you mass destroy entity, you will have a chance to clean up this internal state data automatically. From the outside it seems like you just destroy all entities and everything is clean for real, no lingering states.
     
    daserra likes this.
  4. Enzi

    Enzi

    Joined:
    Jan 28, 2013
    Posts:
    967
    I've a static Reset method in some systems that need it that are called in the bigger reset from a factory.
    2-3 systems in my game have static global flags. Like, is extra attack unlocked? Some will argue that the system does too much and this data should be on a component but if the need ever occurs it can be easily refactored.

    Dictionaries or some complex cached data for the system is something different. When the data is only used locally in the system as a caching mechanism I think it's okay. If it has data for other systems, UI or other externals, big nope. Don't do it. Data integrity is too volatile to be worth it.
     
    daserra likes this.