Search Unity

How to choose a specific component system when several systems may use the same set of componets?

Discussion in 'Entity Component System' started by torano, May 23, 2019.

  1. torano

    torano

    Joined:
    Apr 7, 2017
    Posts:
    46
    Hi. I am very new to ECS and I don't know how to choose a specific component(or even if it is possible).

    Let's say I have DataX which implements IComponetData, and also have SystemA and SystemB which are componet systems (ex. SystemA inherits from ComponentSystem) and both of them use only DataX on their OnUpdate(). Is it possible to make only SystemA work in my scene?

    An idea I came up with is to use a "tag" component which actually contains no data, as MoveUp struct used in FluentQuery scene in the official samples. But I don't think it is a good practice to make a tag component every time I make a system. Any other good way?
     
  2. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    Another way is to declare a single shared component data containing an int value and use EntityQuery.SetFilter for each of your systems. Just make sure to use a different int value in your shared component data for each system.
     
    Last edited: May 24, 2019
  3. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    An example:

    Code (CSharp):
    1.  
    2. using Unity.Entities;
    3. public struct DataX : IComponentData
    4. {
    5. }
    6. public struct SystemIndex : ISharedComponentData
    7. {
    8.     public int Value;
    9. }
    10. public class SystemA : ComponentSystem
    11. {
    12.     private EntityQuery query;
    13.     protected override void OnCreate()
    14.     {
    15.         query = GetEntityQuery(typeof(DataX), typeof(SystemIndex));
    16.         query.SetFilter(new SystemIndex { Value = 0 });
    17.     }
    18.     protected override void OnUpdate()
    19.     {
    20.         Entities.With(query).ForEach((ref DataX dataX) =>
    21.         {
    22.             //Custom code here
    23.         });
    24.     }
    25. }
    26. public class SystemB : ComponentSystem
    27. {
    28.     private EntityQuery query;
    29.     protected override void OnCreate()
    30.     {
    31.         query = GetEntityQuery(typeof(DataX), typeof(SystemIndex));
    32.         query.SetFilter(new SystemIndex { Value = 1 });
    33.     }
    34.     protected override void OnUpdate()
    35.     {
    36.         Entities.With(query).ForEach((ref DataX dataX) =>
    37.         {
    38.             //Custom code here
    39.         });
    40.     }
    41. }
    42.  
     
  4. echeg

    echeg

    Joined:
    Aug 1, 2012
    Posts:
    90

    query.SetFilter(new SystemIndex { Value = 0 });
    Do your know Is faster when?
    OnUpdate(){ ...
    if (SystemIndex.val != 0) return; }
    Or its only syntax sugar?
     
  5. torano

    torano

    Joined:
    Apr 7, 2017
    Posts:
    46
    Thanks for your replying. Your idea is simpler and looks easy to implement. But is there no way to choose a specific component without adding new component data or without editing both system, like choosing a system from a MovoBehaviour class which manages entities?

    What I was trying to do is that I made a very simple system which just counts up a number which is provided by a component data, using Entities.ForEach, and next because I want to make it work parallelly, I made another system which inherits from JobComponentSystem, but then I noticed I could not choose which to work.(Both systems worked at the same time although I wanted only new job system to work.)

    It is ok to add a new component data and edit both systems to my project because they are very simple, if they are complex, that might be a problem. For example, when I want to make a system to debug another complex system, I need to make extra component data and edit the complex system too just for debug...
     
  6. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    If you add this script to your scene, you can select which system runs simply by enabling or disabling the MonoBehaviour:

    Code (CSharp):
    1.  
    2. using Unity.Entities;
    3. using UnityEngine;
    4.  
    5. public class CustomUseJobifiedSystem : UseJobifiedSystem<SystemA, SystemB>
    6. {
    7. }
    8.  
    9. public class UseJobifiedSystem<TSystem, TJobSystem> : MonoBehaviour where TSystem : ComponentSystem where TJobSystem : JobComponentSystem
    10. {
    11.     private TSystem unjobifiedSystem;
    12.     private TJobSystem jobifiedSystem;
    13.     private void Awake()
    14.     {
    15.         unjobifiedSystem = World.Active.GetOrCreateSystem<TSystem>();
    16.         jobifiedSystem = World.Active.GetOrCreateSystem<TJobSystem>();
    17.     }
    18.     private void OnEnable()
    19.     {
    20.         unjobifiedSystem.Enabled = false;
    21.         jobifiedSystem.Enabled = true;
    22.     }
    23.     private void OnDisable()
    24.     {
    25.         unjobifiedSystem.Enabled = true;
    26.         jobifiedSystem.Enabled = false;
    27.     }
    28. }
    29.  
    30.  
     
  7. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    @echeg if performance is what your after, you'll generally want to have as little logic in OnUpdate as necessary.
     
  8. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,657
    Have you considered just setting the Enabled property on SystemB to false, to disable it while you're in your scene?

    (EDIT: oh that's basically what @TRS6123 said :) )
     
  9. torano

    torano

    Joined:
    Apr 7, 2017
    Posts:
    46
    Oh I didn't know a system can be disabled/enabled at runtime. That's really what I wanted. Thanks!
     
  10. torano

    torano

    Joined:
    Apr 7, 2017
    Posts:
    46
    I found putting [DisableAutoCreation] attribute on a system might also be useful. Then do something like this.

    Code (CSharp):
    1. var world = World.Active;
    2.         var simulationSystemGroup = world.GetOrCreateSystem<SimulationSystemGroup>();
    3.  
    4.         var countSystem = world.GetOrCreateSystem<CountSystem>();
    5.         var rangeSystem = world.GetOrCreateSystem<RangeSystem>();
    6.  
    7.         simulationSystemGroup.AddSystemToUpdateList(countSystem);
    8.         simulationSystemGroup.AddSystemToUpdateList(rangeSystem);
    9.  
    10.         simulationSystemGroup.SortSystemUpdateList();
    11.  
    12.         ScriptBehaviourUpdateOrder.UpdatePlayerLoop(world);