Search Unity

Question Handling different "scenes" in ecs?

Discussion in 'Entity Component System' started by Cell-i-Zenit, Nov 16, 2020.

  1. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    290
    Hi,

    I implemented my game core mechanics using ecs (its like a racing game). But now comes the problem in "chaining" the stuff together to a complete game.

    i want to provide the player the possibility to create maps by themselves, so i also need to add an editor.

    Now the problem is that Entities/Systems exist independent of scenes, so i cannot have an editor scene and an ingame scene and just conveniently switch between them.

    What i now did was to have a singleton for each "Scene" -> IngameFlag.cs & InEditorFlag.cs

    The editor systems will run only when RequireSingletonForUpdate<InEditorFlag> is set.
    Same with ingame systems.

    To switch between them i destroy one singleton and add another one.
    There is also a SetupSystem for each "Scene", which creates needed entities on OnStartRunning and destroy the entities on OnStopRunning. In my game i have an IngameSetupSystem which creates/destroy the player for example.

    Am i doing this correctly? Any other recommended ideas?

    EDIT: the good thing is that i can have multiple systems which would normally do the exact opposit of each other, for example i have one EditorCameraSystem and one EngameCameraSystem which only update on the specific "Scene" flag
     
  2. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    This seems like a pretty good candidate for multiple worlds, where each world would have the systems that are needed. But I don't see any problem with your current approach neither, so choose what works best for you.
     
    Samsle likes this.
  3. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    633
    Both options mentionned so far will work, but handling the singleton in every single system can be quite the shore, and i personnaly find juggling between worlds to be troublesome so I'd like to suggest another alternative which would be to put your systems in groups so you have less things to worry about.

    For example RacingModeSimulationGroup VS RaceEditorSimulationGroup, so that you toggle on/off to switch between the features at a somewhat global scale. (you might need several for example RacingModeTransformGroup, RacingModePresentationGroup etc, but still easier to work with imo than the other ways)
     
    WAYNGames likes this.
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    It sounds like you have a working solution. Nothing wrong with it. But I figured I would share mine in case you want to compare or get another take on the problem.

    So my solution is composed of two different pieces:
    1) I couple entities to scenes (not subscenes, real scenes) by destroying all entities during scene changes.
    2) I can conditionally turn off entire ComponentSystemGroups based on custom logic, like checking the value of some singleton-like component.

    With these two pieces, I can treat scenes as if they were completely separate projects when convenient, as long as I put the scene-unique systems in the correct ComponentSystemGroups.

    My solution is public and free to use or steal from if you feel like digging around. These are the links to the documentation for the two pieces:
    https://github.com/Dreaming381/Latios-Framework/blob/v0.2.1/Documentation~/Core/Scene Management.md
    https://github.com/Dreaming381/Latios-Framework/blob/v0.2.1/Documentation~/Core/Super Systems.md
     
    florianhanke likes this.
  5. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    290
    Iam not a fan for multiple worlds since, the editor needs to interact with the environment, but the ingame scene too.

    So either i need to copy them all over on a "scene change" or i just recycle them. This is what i thought so i went with this solution instead of the multiple world solution.

    as you said, this is in theory a good idea, but its quite complicated to create all the needed groups.

    Since iam trying to have lots of separated "modules" eg component groups, the work would be quite heavy

    Thanks for the idea guys, i will stick with my solution as i really like the OnStartRunning/OnStopRunning handling of entities for "specific" scenes.
     
  6. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    290
    Also the handling for the singletons is really easy with this base class here.

    Just inherite from it, then change change OnStart to Start and Onupdate() to Update(SingletonType singleton){}.

    Since i need to pass data to each system via singleton lookup, i can just use this baseclass to abstract all the ugly code away. My systems are really lean now (code wise, performance is not significantly worse, and i prefer less frames for better code)

    I also implemented a commandbuffer wrapper like this, which will create a commandbuffer and pass it into an update method, and will correctly set the dependency in the end.

    Code (CSharp):
    1. public class InputBase<T> : SystemBase where T : struct, IComponentData
    2.  
    3.   {
    4.     protected virtual void Create() { }
    5.     protected new virtual void Update() { }
    6.     protected virtual void Update(T coreInput) { }
    7.  
    8.     protected override void OnCreate()
    9.     {
    10.       RequireSingletonForUpdate<T>();
    11.       Create();
    12.     }
    13.  
    14.     protected override void OnUpdate()
    15.     {
    16.       var input = GetSingleton<T>();
    17.       Update();
    18.       Update(input);
    19.     }
    20.   }
    EDIT: its definitly not really the best design, since i hide the Update() method, but iam not using it anywhere so its working. Maybe i will revisit this in the future