Search Unity

How to separate scenes in DOTS?

Discussion in 'Entity Component System' started by Quit, Apr 15, 2020.

  1. Quit

    Quit

    Joined:
    Mar 5, 2013
    Posts:
    63
    Hello,

    Would somebody know how to separate scenes using Unity DOTS/ECS?

    Example:

    In old Unity, I would have a scene for the main menu, then a scene for the game play area, then a scene for mini game, and then maybe a scene for cinematics. I could control which script ran in which scene and I could have separate state machines running in each scene for loading assets, waiting for player input, maybe animating the background for the main menu etc. I would have control over it.

    In Unity DOTS all systems are instantiated by default. The question is, should I mark all systems [DisableAutoCreation] and instantiate them manually or is it possible to handle this somehow differently? Maybe using Worlds? Subscenes? Currently scenes do not separate SYSTEMS, which means they run exactly the same way in any scene. Hence my MainMenu scene has ShipMovementSystem and so on, which is, of course, not valid.

    Thanks in advance.
     
    Gudarzi and Mikael-H like this.
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Personally I'm a fan of only having 1 scene (or at worst 2, 1 for menu, 1 for game), but I did this before I even started using DOTS.

    Systems don't run without data. It doesn't matter if your menu has a ShipMovementSystem if there is no ship data for it to work on.

    I haven't really played around with architecture recently on how I would build a menu these days, but off top of my head I'd probably put the menu in a subscene and just toggle it to show. Optionally loading the systems in a separate world that I can disable if need be.

    I really dislike the idea of using DisableAutoCreation. Our project, which is hybrid, has over 400 systems from memory and manually initializing of these would be a huge pain.
     
    bb8_1, Gudarzi, Mikael-H and 2 others like this.
  3. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,709
    What your take on breaking it up with subScenes.
     
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    I can't really comment too much on it as I just don't have the experience developing a main menu recently.

    My project at work I only started working on a few months ago had already been in a development for a while before I started and doesn't use subscenes at all (decisions made before I started).

    So only my personal projects use subscenes and building a menu architecture isn't high on my free time priority.

    But yes, if I was to start a looking at a design right now, I'd probably first look at putting the main menu in a subscene and see how it goes.
     
    bb8_1 and NotaNaN like this.
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    The way I do this is I have a system that deletes all entities on scene change, and then I have a mechanism for disabling and enabling groups of systems based on the active scene. (Note: By "scene" I do not mean subscene, and I intentionally check to prevent logic from interfering with subscene streaming.)

    I happen to have a game jam game uploaded where I prototyped my scene management mechanism. Is this somewhat similar to the behavior you are looking for? https://dreaming381.itch.io/density-discrepencies
     
    bb8_1 likes this.
  6. Quit

    Quit

    Joined:
    Mar 5, 2013
    Posts:
    63
    Thanks for your input, guys! I shall investigate on this too.

    I shall check your project tomorrow due to the time limits today. Thanks for sharing it!

    I still don't understand exactly when the systems run, how to change that condition, and when they do not run (apart from manually setting Enabled=false). Sometimes they don't run when there aren't any entities with a specific type. Sometimes they don't run just Entities.ForEach, but if I had something in OnUpdate just before the Entities.ForEach, it would run that part only, which may sometimes crash the system due to my project being in a different scene.

    Plus I noticed that if I set Enabled=false in OnCreate(), it doesn't even initialize the system, but if I set Enabled=false in OnUpdate, it initializes the SYSTEM, but does not run it. Bizarre.
     
  7. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,709
    Im the least qualified to help you but on a high level , a system does an entity query implicitly or you can do it explicitly. If the query finds entities matching the query the system runs. You can put a filter on the query or tag entities so it will only run on entity that have change or potentially changed. So you really dont have to tun the system off because if there is nothing to do then it will do noting if setup that way. But Im still learning this stuff to take it with a grain of salt
     
  8. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    792
    I think it would be necessary to select a system for scenes. Especially if you have a bigger game with hundreds or thousands of systems, you don't want bootstrap all systems manually. The whole overheat that arises when all systems are created and initalized (OnCreate()), even if one only needs 2-3 systems in the scene.

    However, I do not know whether Unity starts the systems, when opening a scene or once when starting the game?
     
  9. Quit

    Quit

    Joined:
    Mar 5, 2013
    Posts:
    63
    It seems SYSTEMS don't have a concept of old Unity scenes as such. I started using my own System Groups to group the systems I need to update and where I need to update them, however, I'm still thinking how to solve the issues with the scenes themselves. I don't want to have MainMenu systems dangling around when I'm in the game scene area.

    Can anyone from @Unity explain how to separate scenes/SYSTEMS? If I want to have MainMenu scene with N amount of SYSTEMS, but then in GamePlay scene, I don't want MainMenu scene SYSTEMS anymore, but want other M amount of SYSTEMS. Do I initialize them manually? Is there an attribute to define which scene it belongs to? How should I deal with 100s of systems, if only handsome are needed in a specific scene?
     
    Last edited: Apr 16, 2020
  10. Quit

    Quit

    Joined:
    Mar 5, 2013
    Posts:
    63
    I looked at your project and yes, it's kinda what I want to do. Have a main menu scene, and once the button is clicked, I'd load a different scene with gameplay elements in it.

    However, I don't know how you implemented it behind the scenes :(
     
  11. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    So I share the framework I reuse for all my games publicly here: https://github.com/Dreaming381/Latios-Framework
    However, the version that is up there is old and broken. I mostly published it to get early feedback on the design direction. I am currently QA-ing 0.2.0 which should be much more stable and usable once I release it. Here's a few snippets from the new version which cover this functionality.

    First, is the ability to destroy all entities on scene change. You can't create an EntityQuery with only exclude components so I tag all entities first.
    Code (CSharp):
    1. using Unity.Entities;
    2. using UnityEngine.SceneManagement;
    3.  
    4. namespace Latios.Systems
    5. {
    6.     internal struct LatiosSceneChangeDummyTag : IComponentData { }
    7.  
    8.     [AlwaysUpdateSystem]
    9.     public class DestroyEntitiesOnSceneChangeSystem : SubSystem
    10.     {
    11.         private EntityQuery m_destroyQuery = null;
    12.  
    13.         protected override void OnCreate()
    14.         {
    15.             m_destroyQuery              = Fluent.WithAll<LatiosSceneChangeDummyTag>().Without<WorldGlobalTag>().Without<WorldGlobalTag>().Build();
    16.             SceneManager.sceneUnloaded += RealUpdateOnSceneChange;
    17.         }
    18.  
    19.         protected override void OnUpdate()
    20.         {
    21.         }
    22.  
    23.         private void RealUpdateOnSceneChange(Scene unloaded)
    24.         {
    25.             if (unloaded.isSubScene)
    26.                 return;
    27.  
    28.             EntityManager.AddComponent<LatiosSceneChangeDummyTag>(EntityManager.UniversalQuery);
    29.             EntityManager.DestroyEntity(m_destroyQuery);
    30.             EntityManager.RemoveComponent<LatiosSceneChangeDummyTag>(EntityManager.UniversalQuery);
    31.             latiosWorld.CreateNewSceneGlobalEntity();
    32.         }
    33.     }
    34. }
    Next, I have this specialized ComponentSystemGroup subclasses which allow me to control whether each system should run using a custom ShouldUpdateSystem callback. I often override this callback on ComponentSystemGroups directly so that the children systems don't have to duplicate the check.

    Code (CSharp):
    1. using System;
    2. using System.ComponentModel;
    3. using Unity.Entities;
    4.  
    5. namespace Latios
    6. {
    7.     public abstract class RootSuperSystem : SuperSystem
    8.     {
    9.         protected override void OnUpdate()
    10.         {
    11.             if (ShouldUpdateSystem())
    12.                 base.OnUpdate();
    13.         }
    14.     }
    15.  
    16.     public abstract class SuperSystem : ComponentSystemGroup, ILatiosSystem
    17.     {
    18.         public LatiosWorld latiosWorld { get; private set; }
    19.  
    20.         public ManagedEntity sceneGlobalEntity => latiosWorld.sceneGlobalEntity;
    21.         public ManagedEntity worldGlobalEntity => latiosWorld.worldGlobalEntity;
    22.  
    23.         public FluentQuery Fluent => this.Fluent();
    24.  
    25.         public virtual bool ShouldUpdateSystem()
    26.         {
    27.             return Enabled;
    28.         }
    29.  
    30.         [EditorBrowsable(EditorBrowsableState.Never)]
    31.         protected sealed override void OnCreate()
    32.         {
    33.             if (World is LatiosWorld lWorld)
    34.             {
    35.                 latiosWorld = lWorld;
    36.             }
    37.             else
    38.             {
    39.                 throw new InvalidOperationException("The current world is not of type LatiosWorld required for Latios framework functionality.");
    40.             }
    41.             CreateSystems();
    42.         }
    43.  
    44.         [EditorBrowsable(EditorBrowsableState.Never)]
    45.         protected override void OnUpdate()
    46.         {
    47.             foreach (var sys in m_systemsToUpdate)
    48.             {
    49.                 try
    50.                 {
    51.                     if (sys is ILatiosSystem latiosSys)
    52.                     {
    53.                         if (latiosSys.ShouldUpdateSystem())
    54.                         {
    55.                             sys.Enabled = true;
    56.                             sys.Update();
    57.                         }
    58.                         else
    59.                         {
    60.                             sys.Enabled = false;
    61.                         }
    62.                     }
    63.                     else
    64.                     {
    65.                         sys.Update();
    66.                     }
    67.                 }
    68.                 catch (Exception e)
    69.                 {
    70.                     UnityEngine.Debug.LogException(e);
    71.                 }
    72.  
    73.                 if (World.QuitUpdate)
    74.                     break;
    75.             }
    76.         }
    77.  
    78.         [EditorBrowsable(EditorBrowsableState.Never)]
    79.         public sealed override void SortSystemUpdateList()
    80.         {
    81.             // Do nothing.
    82.         }
    83.  
    84.         public EntityQuery GetEntityQuery(EntityQueryDesc desc) => GetEntityQuery(new EntityQueryDesc[] { desc });
    85.  
    86.         #region API
    87.  
    88.         protected abstract void CreateSystems();
    89.  
    90.         public ComponentSystemBase GetOrCreateAndAddSystem(Type type)
    91.         {
    92.             var system = World.GetOrCreateSystem(type);
    93.             AddSystemToUpdateList(system);
    94.             return system;
    95.         }
    96.  
    97.         public T GetOrCreateAndAddSystem<T>() where T : ComponentSystemBase
    98.         {
    99.             var system = World.GetOrCreateSystem<T>();
    100.             AddSystemToUpdateList(system);
    101.             return system;
    102.         }
    103.  
    104.         public void SortSystemsUsingAttributes()
    105.         {
    106.             base.SortSystemUpdateList();
    107.         }
    108.  
    109.         #endregion API
    110.     }
    111. }
    112.  
    113.  
    Lastly, I get the active scene with
    SceneManager.GetActiveScene().name

    I stash that in a component I can check in ShouldUpdateSystem.

    Hope that helps!
     
  12. Quit

    Quit

    Joined:
    Mar 5, 2013
    Posts:
    63
    Thanks. That's what I pretty much had in mind. Though didn't want to write it myself. Hoped that Unity had something under their sleeve...
     
  13. RuslanSmirnov

    RuslanSmirnov

    Joined:
    Jun 13, 2019
    Posts:
    7
    ...

    Why It's Hard to do Simple Things?
     
  14. Radu392

    Radu392

    Joined:
    Jan 6, 2016
    Posts:
    210
    I think most of us here come from a programming background and we all know that at the end of the day, it's not really a matter of 'simplicity', but a matter of time. Those who published games before know just how many features and suggestions our customers have and although most suggestions sound 'simple' on their own, the fact that there are so many would take a very long time to implement. Well, it's the same with Unity DOTS. There's still a lot to do, so give them some time.
     
  15. RuslanSmirnov

    RuslanSmirnov

    Joined:
    Jun 13, 2019
    Posts:
    7
    https://unity.com/dots

    But owners of unity tell us differently. Or it's still alpha-beta test?)
     
  16. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Dots is still in preview. I agree the linked page is a bit confusing on the current state of DOTS. It mentions that it is preview packages on the page, but I do think it could be a lot clearer. I'll follow up with marketing team on making it clearer.
     
    RuslanSmirnov likes this.
  17. RuslanSmirnov

    RuslanSmirnov

    Joined:
    Jun 13, 2019
    Posts:
    7
    Okey... thank you very much!