Search Unity

ECS Hybrid Architectural Approaches

Discussion in 'Entity Component System' started by JeffTheCampbell, Sep 18, 2019.

  1. JeffTheCampbell

    JeffTheCampbell

    Joined:
    Jul 11, 2018
    Posts:
    35
    Looking at several different popular ECS threads and the Entity Component sample project, I'm having a hard time distinguishing how to currently leverage ECS using a hybrid approach that goes beyond simple proof of concept projects; much of this limitation seems to be due to minimal component support that is still ongoing development (expected while it is in a preview package). There seem to be a few architectural patterns for communicating between ECS systems and Monobehaviors currently, but I'm unsure of what is recommended and what are hacky workarounds that will go away in the near future. These are a few of the ones I've seen (and there may be others I have not)
    • Implement a component system whose purpose is to interact with a Monobehavior Singleton for native Unity functionality not currently available. Examples might be triggering a sound, playing a particle system, pooling objects, or other Unity component interactions not available from ECS currently.
    • There seem to be some references with regards to syncing Entities and native Unity Components via GameObjectEntity in this thread here (https://forum.unity.com/threads/keeping-entity-and-gameobject-in-sync.524237/), but there seems to be back and forth as to whether or not this is working properly or should work in the future.
    Ultimately, I'm looking for concrete hybrid architectural approaches that would work with the current ECS preview packages that would allow for some level of standard Unity functionality beyond transform/render mesh manipulation or code-only approaches. Failing that, any information on where ECS currently falls short for these types of interactions would be helpful as well. Examples of desired functionality include:
    • Playing audio
    • Playing particle systems
    • Otherwise interacting with native Unity components or non-ECS systems
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    There is DOTS, thread talking about Audio with ECS.
    Particles can be made with DOTS. So I assume, such tool will be available at some point.

    Otherwise, you may want interact with GameObjects on main thread, or via Jobs. Which tweening approach you will take is up to you. For example if you want at current state control lights, you can match Game Object references to entity with NativeArray, HashMaps, Dictionary would work as well, or even simple List/array. Just some options.
     
  3. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,270
    For interacting with GameObject world, the most common approach is to use EntityManager.AddComponentObject.

    If you just need a GameObject to do something that isn't supported in ECS yet, the best approach is to manage a GameObject pool and have a system that syncs it with ECS data. The hybrid renderer does this. But if you need the entities to have ownership and more persistent state, you can use ISystemStateComponentData which holds an index to a managed List of GameObjects.
     
    MostHated likes this.
  4. JeffTheCampbell

    JeffTheCampbell

    Joined:
    Jul 11, 2018
    Posts:
    35
    I'm looking less for ways that content might be authored exclusively for DOTS in the future and more for ways that the ECS portion of DOTS can be used with a hybrid approach now.

    Manipulating transforms even in a non-hybrid approach is easy at the moment since there is native Unity support for doing so both from ComponentSystems, JobComponentSystems and Jobs. Almost all of the current ECS samples are various takes or approaches on transform manipulations. There is less of a clear path for doing something like triggering a sound or playing a particle system which does not currently have a convertible ECS component from the older Unity component and thats what I'm trying to understand how it could be accomplished.

    A collection indexing entities to an older Unity component or Monobehavior-derived class like you've mentioned seems like a way to go, but in practice I am not sure how to go about accomplishing this type of bridge. For example, entities are typically created via the PostUpdateCommands command buffer which delays instantiation of the entity to later in the frame and from what testing I've done it seems like it would not be possible to get an older Unity component reference at this point. Would you create a different component system that executes later or after that frame to sync up these references (now there are two different ComponentSystems, one for instantiation of prefabs as entities and one for syncing component refs)? Are there any examples you could point me to that would demonstrate this pattern?
     
  5. JeffTheCampbell

    JeffTheCampbell

    Joined:
    Jul 11, 2018
    Posts:
    35
    This is interesting; usage of this would work for components that were not present at instantiation or could be added to in addition to existing components. What about for existing components on a prefab that has been instantiated as an Entity? Like I mentioned above, entities are typically instantiated later in the frame via PostUpdateCommands and it seems like it would not be possible to get access to existing Unity components. Would you implement a component system that syncs up existing components later in the frame or on the next frame?

    Pooling GameObjects/Monobehaviors is likely the approach I am going to take for many non-ECS objects, but the part that eludes me is how to sync up entity and component references.

    For example, lets say I have an entity that I am simulating in a ComponentSystem and some logic dictates a sound, particle, and/or animation event should take place on a Unity or Monobehavior on that entity. What conversion/lookup logic would be needed to get the GameObject from that entity?

    In the opposite direction, lets say I have a rigidbody/collider on an entity that I want to raycast to outside of ECS, but have be translated to some logic executed on that entity in a component system. I'd need to have a way of looking up the entity from the GameObject so that I could execute the proper action for that entity.
     
  6. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,270
    ParticleSystemTag : IComponentData {} and ParticleSystemIndex : ISystemStateComponentData { public int index; }
    Anything that has a ParticleSystemTag and not a ParticleSystemIndex gets processed by a system that adds the index and hooks it up with a pool. Anything that has a ParticleSystemIndex and not a ParticleSystemTag is an entity being destroyed and the index can be released to the pool and the ParticleSystemIndex component can be removed.

    Same idea except you would pool a GameObject with a custom MonoBehaviour that has settable Entity and EntityManager fields. Or just use Unity.Physics.
     
    florianhanke likes this.
  7. JeffTheCampbell

    JeffTheCampbell

    Joined:
    Jul 11, 2018
    Posts:
    35
    How do you get a GameObject reference from an entity or lookup the entity a GameObject is associated with? Is there an Entity utility class that you can use for this purpose?
     
  8. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
  9. JeffTheCampbell

    JeffTheCampbell

    Joined:
    Jul 11, 2018
    Posts:
    35
    Not to be rude, but that is not what I'm asking about. I've already mentioned several times that Transforms have native support for manipulation from ECS and Jobs and so you don't need to do any hybrid bridging between ECS and traditional Unity components or Monobehavior-derived classes. The newer native collections are also not relevant; my question is aimed at how you retrieve a given GameObject from an Entity and vice versa how can you determine if a GameObject has an associated entity with it.

    See my question below for more reference as to what I'm asking for rather than cross-posting links that aren't relevant.

     
  10. psuong

    psuong

    Joined:
    Jun 11, 2014
    Posts:
    126
    1. Given an entity how can you retrieve a gameObject?
    Assuming that a gameObject is converted its entity format using the conversion API (the ConvertToEntity MonoBehaviour), an entity with a ParticleSystem MonoBehaviour component will have a <ParticleSystem> type into its EntityArchetype.

    upload_2019-9-19_11-26-42.png
    upload_2019-9-19_11-44-29.png

    2. Given a gameObject how can you retrieve the associated entity?
    AFAIK, there's no direct way to get a gameObject -> Entity, you can certainly grab the MonoBehaviour components on the gameObject using an EntityQuery. The reason I say that is because when you convert a gameObject to its entity format, the entity will not have a Archetype with type<GameObject>. Of course you can always grab it via a MonoBehaviour component instead.

    So let's say if you wanted to grab the ParticleSystem from GameObject(1) or any entity with a ParticleSystem, you would create an EntityQuery like so:

    Code (CSharp):
    1. class ParticleSystemIteration : ComponentSystem {
    2.   EntityQuery particleQuery;
    3.   protected override void OnCreate() {
    4.     particleQuery = GetEntityQuery(typeof(ParticleSystem));
    5.   }
    6.   protected override void OnUpdate() {
    7.     Entities.With(particleQuery).ForEach((ParticleSystem ps) => {});
    8.     // if you need the entity
    9.     Entities.With(particleQuery).ForEach((Entity entity, ParticleSystem ps) => {});
    10.   }
    11. }
    For a variation of the params in the lambda expression, I would look into the delegates supported in EntityQueryBuilder.
     
    Last edited: Sep 19, 2019
    florianhanke likes this.
  11. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,270
    I just looked at the code: CopyTransformToGameObjectSystem.cs, TransformAccessArrayIterator.cs, and ComponentArray.cs. To my surprise, the code allocates GC whenever there is a structural change to any of the entities with a Transform ComponentObject attached. It really is a makeshift bridge just to unblock people and not really something everyone should use.

    Everyone's hybrid needs are a little bit different, and since hybrid is only a temporary thing until Unity makes the full transition, Unity isn't really interested in spending the resources to create a true hybrid solution when those resources could be put towards reaching the pure solution faster, and so Unity has instead given us a collection of building blocks so that we can build our own to our needs.
     
    psuong likes this.
  12. dthurn

    dthurn

    Joined:
    Feb 17, 2015
    Posts:
    77
    I definitely thought GameObjectEntity was how you were supposed to solve this. Did that become discouraged in some way in the last few months?

    You could also just store the Entity as a field on a MonoBehaviour in order to do the reverse mapping.
     
  13. JeffTheCampbell

    JeffTheCampbell

    Joined:
    Jul 11, 2018
    Posts:
    35
    I'm not sure. I'm having a hard time tracking down any information on what `GameObjectEntity`'s purpose is or how its used. Storing the Entity as a field on a MonoBehaviour does seem like a valid usage (for now) of doing the GameObject to Entity mapping.

    I didn't realize ParticleSystem was supported by the EntityConversion process; I had thought this had minimal support limited to Transforms and MeshRenderers only right now. I'll have to check this out.


    Is it possible to get access to MonoBehaviour components on entities? I didn't realize this was supported; I thought these type of queries were limited to ECS components only.
     
  14. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    GameObjectEntity was pseduo depreciated 6 months ago. While not officially depreciated, all the proxy components that went with it were depreciated so it can be assumed it'll be removed at some point.

    Entity conversion basically replaced it and should be used.
     
    Last edited: Sep 25, 2019
    JeffTheCampbell likes this.
  15. psuong

    psuong

    Joined:
    Jun 11, 2014
    Posts:
    126

    The Unity MonoBehaviour Component will be linked to the entity, but won't live in the Chunk, (I believe this might be done through a look up, I haven't fully looked into it). The EntityQueryBuilder should show you how many class based components (MonoBehaviours) you can fit in a given builder. They usually look like EntityQueryBuilder.F_EC, etc,

    where
    C -> Component (MonoBehaviour),
    D -> IComponentData
    S -> ISharedComponentData
    B -> DynamicBuffer<T> where T : IBufferElementData

    1. Is it possible to get access to MonoBehaviour components on entities?
    So knowing how the query builders work, it is possible to get MonoBehaviour components from the entity, the gameObject must just be linked to an entity and this is usually done already by the conversion workflow.

    Otherwise you can do, EntityManager.GetComponentObject on the entity in your function.