Search Unity

Thoughts on hybrid mode

Discussion in 'Entity Component System' started by SubPixelPerfect, Apr 17, 2018.

  1. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    Pure ECS is lacking lots of system to make real games right now
    and probably it'll take not one year to rewrite all existent systems to use pure data oriented approach

    But hybrid approach based on GameObjectEntity looks a bit wired for me.
    Having a MonoBechaviour attached to entity brings few problems:
    1. It violates principles of data oriented design - components are objects that contain logic
    2. It makes serialisation/deserealisation of an entity to be a complicated thing
    3. you'll need to make a huge refactoring when pure systems arrive
    4. you can't use Jobs

    Also i think that hybrid mode should
    create game objects for each entity,
    not entity for each game object


    Why not to go a wrapper way?
    It is possible to create systems that operate on pure DataComonents but inside use GameObjects to do their job. And if data-api be the same, you'll be able simply to switch to pure system when it'll arrive.

    For sure this wrapped system going to be slow, because it'll need to copy data each frame ecs>oop>ecs.
    But it'll allow to start developing in data oriented way.



    I've made a test project that wraps physics and mouse events, and it works totally fine for me.

    hybrid-wrapper-low-res.gif
    i have few systems there:
    1) BoxEmitterSystem - creates entities with a small delay with randomized position
    those entities have 4 components: prefab(contains an id of prefab), position(float3), rotation(float3), clickable(empty)
    2) GameObjecManagerSystem - creates/removes GameObjects for each Entity with prefab component and maintain a dictionary that maps entity-to-gameobject
    3) GameObjectTrasformationSystem - keeps Entity position and rotation synchronized to GameObject (actually 2 systems there: one to read game object data, and second to write it) it is possible to synchronize any MonoBehavior property to pure ecs component this way
    4) GameObjectClickSystem - creates event-entity with click-target-entity after clicking on GameObject
    5) ClickEventsHandlerSystem - consumes events and removes entities that was clicked

    (I can share it if someone interested)

    as a result I have working physics, and only pure data


    What do you think?


    (sorry my English - it's not perfect i know)
     
    Last edited: Apr 17, 2018
    sngdan likes this.
  2. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    I did this in the same way. Writing some systems that will synchronize my data with the real world.
    But I skipped it because it cause me some problems and the trade off wasn't that big. Instead I had to write synch systems for different mono components...

    If you want to use Jobs or you have some other problems with the hybrid mode, you can do it this way.
    I went back to hybrid.
    (I'm currently prototyping)

    But I think it's a way you can go...
     
    SubPixelPerfect likes this.
  3. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    I'm already going this way )

    My question was mostly to unity development team, is it reasonable for unity to go this way as well?

    yes I'm thinking now about "generic synchronizer" that be able to synch any property of any mono component to custom IComponentData on corresponding entity
     
    Last edited: Apr 17, 2018
  4. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Well I'm interested in the solution, too. Notice that generic systems arn't supported by the ecs yet.

    You can write some, but you have to call the OnUpdate Method manually. And I think dependencies won't be resolve as well. (ReadOnly, WriteOnly...)
     
  5. floboc

    floboc

    Joined:
    Oct 31, 2017
    Posts:
    91
    One thing that I find particularly annoying when using the hybrid approach is to deal with instantiating prefabs that have components attached to it (using a component wrapper).
    Indeed, there is nothing equivalent to PostUpdateCommand.CreateEntity() for GameObjects.
    Thus I have been forced several times to write "spawn systems" that only do something like :

    Code (CSharp):
    1.  
    2.     [Inject] private SomeGroup group;
    3.  
    4.     protected override void OnUpdate()
    5.     {
    6.         List<SomeSpawnData> toSpawn = new List<SomeSpawnData>();
    7.  
    8.         for (int i = 0; i < group.Length; i++)
    9.         {
    10.             toSpawn.Add(new SomeSpawnData {
    11.                  //spawn info here
    12.             });
    13.             PostUpdateCommands.DestroyEntity(group.Entities[i]);
    14.         }
    15.  
    16.         foreach (SomeSpawnData data in toSpawn)
    17.         {
    18.             //instantiate game object here and use spawn data to set entity components
    19.         }
    20.     }
    21.  
    This makes it sadly impracticable and forces us to have a big "SomeSpawnData" structure that contains all the possible things we want to do when spawning an entity (for instance adding other components in some specific cases, etc.)
     
  6. bcondran

    bcondran

    Joined:
    Jul 2, 2012
    Posts:
    2
    @SubPixelPerfect I'd be curious to see how you went about things if you're still open to sharing.
     
  7. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    Last edited: Apr 19, 2018
    optimise likes this.
  8. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,129
  9. floboc

    floboc

    Joined:
    Oct 31, 2017
    Posts:
    91
    I just tried it, you have to attach "HybridWorld" and "PrefabsList" to the GameSettings. In the prefab list, set its size to 1 and add the box prefab (you might need to also add a material to the prefab).
    On the box prefab, attach the script "MouseEventGenerator" and here you go ;)

    Also, you have to remove some namespace in one of the script file. Somethinf like PureECS.something if I remember right
     
    optimise likes this.
  10. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,129
    I think there's one more missing script at box prefab. What is that script?

    upload_2018-4-19_21-51-50.png
     
  11. floboc

    floboc

    Joined:
    Oct 31, 2017
    Posts:
    91
    Just remove it
     
  12. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    strange that attached scripts are lost, i'll check
     
  13. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    added meta files to git, now it should work.

    sorry that it wasn't there - it is first time i'm sharing unity project, had to check it myself first before posting
     
    Last edited: Apr 19, 2018
    MadeFromPolygons, optimise and FROS7 like this.
  14. Tudor_n

    Tudor_n

    Joined:
    Dec 10, 2009
    Posts:
    359
    This approach is quite nice but its missing one big thing imho. GameObject to entity allows complex prefabs to be spawned in one go ( think of hierarchical prefabs with ECS entities and components on all/ some children ). This is easily achievable with only very little boilerplate.

    You can still do this here as well, but the workflow is anything but natural as you'd have to link a prefab manually for each child then also handle parenting, etc.
     
  15. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    complex object structures is absolutely unrelated to problem i'm talking about - purity of hybrid mode

    When switching from OOP to ECS - you have to start thinking differently,
    it is hard to forget a habit of thinking by objects

    close Hierarchy inspector and look only on Entity Debugger, all is data now

    if you need any data structure other than list - tree, or graph, or grid, simply introduce a new entity or component representing a link between nodes.


    Unfortunateley unity don't have a runtime load format for entities:
    - the only way to construct a pure-data-entity is programmatically using EntityManager API, there is no gui tool for it right now
    - there is no way to save current entity state, even if it contains only pure IComponentData structs there is no good way to serialize all it's components
    - there is no thing like SerializedEntity - you can't tweak entity properties in inspector

    Hope this is coming very soon.
    ( https://forum.unity.com/threads/ser...onents-of-a-given-entity.524553/#post-3454605 )
     
    Last edited: Apr 21, 2018
  16. Tudor_n

    Tudor_n

    Joined:
    Dec 10, 2009
    Posts:
    359
    Oop and prefabs with hierarchies for the sake of workflow have nothing in common. It is mostly unrelated to one's chosen programming paradigm.

    Not sure if you've shipped games with both prefab and template ( flat archetype ) based workflows. We have, and templates are a nightmare, for everyone involved. Particularly designers and artists, but not only.

    Even with pure ecs you can keep your data in prefabs before creating entities ( flat or otherwise ) and this is what you lose with this system. If it helps, think of automating linkage and all the manual labour that comes with it.
     
  17. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    sure game object is a convenient thing, i'm not saying anything about it, but GameObjectEntity puts MonoBechaviour Objects to Entities, i'm complaining only about it
     
  18. floboc

    floboc

    Joined:
    Oct 31, 2017
    Posts:
    91
    I see that your approach requires to use a lot of GetComponent<> calls on GameObjects, for instance to update its Transform from your Position component.

    Isn't that specifically slow ?

    What do you think about instead passing the EntityManager and Entity to a MonoBehaviour and having it call EntityManager.GetComponentData<Position>(Entity) to update it Transform ?

    Do you know which one is faster between EntityManager.GetComponentData and Object.GetComponent ?
     
  19. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    You won't have to call EntityManager.GetComponentData and Object.GetComponent at all!

    You just do the following in your sync system:

    ECS -> Vanilla Unity
    Code (CSharp):
    1. struct SyncData {
    2.        public ComponentArray<Tranform> transforms;
    3.        public ComponentDataArray<Position> positions;
    4.        public ComponentDataArray<Rotation> rotations;
    5.        public int Length;
    6. }
    7.  
    8. [Inject] SyncData data;
    9. ...
    10.  
    11. Transform transform = data.transforms[i];
    12. PositionComponent position = data.positions[i];
    13. RotationComponent rotation = data.rotations[i];
    14.  
    15. transform.position = position .value;
    16. transform.rotation = rotation .value;
    17.  
    18.  
     
  20. floboc

    floboc

    Joined:
    Oct 31, 2017
    Posts:
    91
    This does not seem to be compatible with the approach proposed here (see first post). Or maybe I misunderstood what you meant ?

    To complete : let's suppose you want to instantiate a new Entity. Currently there is no way to do this in PostUpdateCommands using a GameObject with the GameObjectEntity on it (you can only call the usual Instantiate function which breaks the injected data if there are components attached to it). So the idea is that instead you only work with pure ECS and make a "bridge" with unity game object using a dictionnary that maps entity to gameobject, and instiate/destroy prefabs as needed
     
    SubPixelPerfect likes this.
  21. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    yes this is a good idea, synchronization code may be placed inside MonoBehaviour

    have no idea
    Performance wasn't something i wanted to achieve here, key goal is to use Pure ECS with systems which use GameObjects internally (as temporary replacement for missing pure systems)

    The whole post is about avoiding this
    public ComponentArray<Tranform>transforms;
     
    Last edited: Apr 25, 2018
  22. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Ah ok so I've misunderstood it! :D
     
  23. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    451
    It looks ok for small an amount of gameobjects but when I have instantiated about 3000 of those cubes than those systems making synchronization took about 7ms combined on hi-end PC.
     
    twobob likes this.
  24. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    yes this is not about performance
    this is about using pure ecs approach for game logic, with game-object-based rendering/physics/whatever, while similar ecs-systems do not exist yet
     
  25. deadwisdom

    deadwisdom

    Joined:
    May 16, 2013
    Posts:
    1
    @SubPixelPerfect -- How did this go? Did you follow this way any more? See anyone else doing it?

    I really like this approach, because I want to do most of the things in ECS, but have some game objects that can't be represented in ECS sort of *shadow* the data. But I can't seem to find anyone else doing it.