Search Unity

How can set Parent-Child relationships and Indexes in DOTS?

Discussion in 'Data Oriented Technology Stack' started by jintaenate, Aug 8, 2019.

  1. jintaenate

    jintaenate

    Joined:
    Sep 12, 2018
    Posts:
    16
    I recently have been doing plant and satellite relationship in DOTS.

    I made system that satellite moving around plant entity while plant entity to move forward.

    After that, i order to destroy plant entity then i want satellite entity destroy together with plant.

    How can i set Parent-Child relationships like gameobject??
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,428
    Just look at conversion workflow, how it works, look at transform system and how it deal with parent-child relationships, look at Parent, LocalToParent components, Child buffer, LinkedEntity buffer.
     
  3. snotbubblelou

    snotbubblelou

    Joined:
    Jan 17, 2013
    Posts:
    5
    I feel your pain jintaenate I had to look this up myself. Instead of a RTFM answer, here is how I abstracted SetParent for DOTS. I hope this helps

    Code (CSharp):
    1. public static void SetParent(EntityManager dstManager, Entity parent, Entity child, float3 localTranslation, float3 localRotation, float3 localScale)
    2.     {
    3.         //set the child
    4.         if (!dstManager.HasComponent<LocalToWorld>(child))
    5.             dstManager.AddComponentData(child, new LocalToWorld { });
    6.  
    7.         if (!dstManager.HasComponent<Translation>(child))
    8.             dstManager.AddComponentData(child, new Translation { Value = localTranslation });
    9.         else
    10.             dstManager.SetComponentData(child, new Translation { Value = localTranslation });
    11.  
    12.         if (!dstManager.HasComponent<Rotation>(child))
    13.             dstManager.AddComponentData(child, new Rotation { Value = quaternion.Euler(localRotation) });
    14.         else
    15.             dstManager.SetComponentData(child, new Rotation { Value = quaternion.Euler(localRotation) });
    16.  
    17.         if (!dstManager.HasComponent<NonUniformScale>(child))
    18.             dstManager.AddComponentData(child, new NonUniformScale { Value = localScale });
    19.         else
    20.             dstManager.SetComponentData(child, new NonUniformScale { Value = localScale });
    21.  
    22.         if (!dstManager.HasComponent<Parent>(child))
    23.             dstManager.AddComponentData(child, new Parent { Value = parent });
    24.         else
    25.             dstManager.SetComponentData(child, new Parent { Value = parent });
    26.  
    27.         if (!dstManager.HasComponent<LocalToParent>(child))
    28.             dstManager.AddComponentData(child, new LocalToParent());
    29.  
    30.         //set the parent
    31.         if (!dstManager.HasComponent<LocalToWorld>(parent))
    32.             dstManager.AddComponentData(parent, new LocalToWorld { });
    33.  
    34.         if (!dstManager.HasComponent<Translation>(parent))
    35.             dstManager.AddComponentData(parent, new Translation { Value = Vector3.one });
    36.  
    37.         if (!dstManager.HasComponent<Rotation>(parent))
    38.             dstManager.AddComponentData(parent, new Rotation { Value = Quaternion.identity });
    39.  
    40.         if (!dstManager.HasComponent<NonUniformScale>(parent))
    41.             dstManager.AddComponentData(parent, new NonUniformScale { Value = Vector3.one });
    42.  
    43.     }
     
  4. Abbrew

    Abbrew

    Joined:
    Jan 1, 2018
    Posts:
    145
    Another way of doing this is to have an entity have a component that hold another entity. Like
    Code (CSharp):
    1. public struct Arm : IComponentData
    2. {
    3.      public Entity armEntity
    4. }
    If you want to access the armEntity, have a job, access the component using ComponentDataFromEntity<Arm>, and use another ComponentDataFromEntity<XXX> to access the armEntity's components
     
  5. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    18
    I agree the RTFM answer is not particularly helpful. To create simple parenting, on the child you have to add a 'Parent' component AND a 'LocalToParent' component.

    Code (CSharp):
    1.            
    2. entityManager.AddComponentData(myChildEntity, new Parent { Value = myParentEntity });
    3. entityManager.AddComponentData(myChildEntity, new LocalToParent { });
    4.  
    This works for parenting normal entities, but you need more stuff to get it to work if you're using the ConvertToEntity workflow and want use those things in your heirarchy. That's where the 'LinkedEntity' buffer and 'Child' Buffers come in to play, I think, but I don't know how to use those yet... so yeah, I am RTFM'ing it right now without much success.

    And that's all I know for now.
     
    Last edited: Sep 12, 2019
  6. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    277
    Entities within a LinkedEntityGroup buffer are all created or destroyed together, giving you that traditional destroy the parent & destroy its children relationship from gameobjects.

    pseudocode -

    Code (CSharp):
    1. var buffer = EntityManager.AddBuffer<LinkedEntityGroup>(parentEntity);
    2. buffer.add(childEntity);
     
  7. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    18
    Okay, so do LinkedEntityGroups work in a hierarchy too? For as an example, I have a hierarchy like this:

    Code (CSharp):
    1.  
    2. Player
    3. |
    4. +---> Arm
    5.        |
    6.        +---> Hand
    7.  
    I want to attach a 'Sword' entity as a child of the 'Hand' entity. So I do this:

    Code (CSharp):
    1.  
    2. entityManager.AddComponentData(SwordEntity, new Parent { Value = HandEntity });
    3. entityManager.AddComponentData(SwordEntity, new LocalToParent { });
    4.  
    I understand that the LinkedEntityGroup will be on the 'Player' object, but not on the Arm or Hand objects.
    So I add a LinkedEntityGroup to the 'Hand' Entity, then add the Sword to that? Or do I have walk the tree up to the root and add it to the 'Player' objects group?

    Code (CSharp):
    1.  
    2. // Just add the buffer to the hand entity and it works?
    3. // (note: tried this and it doesn't seem to work for me)
    4. var buffer = EntityManager.AddBuffer<LinkedEntityGroup>(HandEntity);
    5. buffer.add(SwordEntity);
    6.  
    7. OR
    8.  
    9. // Add it to the root object
    10. // (note: This works as expected - destroying the player destroys the sword)
    11. var buffer = EntityManager.AddBuffer<LinkedEntityGroup>(PlayerEntity);
    12. buffer.add(SwordEntity);
    13.  
    I guess I'm trying to avoid having to know what the root object is if I'm parenting something to a entity deeper in the tree. Maybe that's not possible.

    Also... what's the Child buffer for that eizenhorn mentioned? I can't seem to find an example of how to use it.
     
  8. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    277
    My understanding is the LinkedEntityGroup doesnt care about what entities are in a hierarchy or not, if an entity has a LinkedEntityGroup buffer any stored in that buffer will be created or destroyed along with said entity.
    That said if a child entity has a linkedentitygroup and number of entities stored, and the parent has the child as a different linkedentity group and the parent is destroyed(or these can be unrelated hierarchy wise and only linked through the LinkedEntityGroup), I would assume all linkedentities of the child should be destroyed but I havent specifically tested that scenario.

    The child buffer is just a buffer of all child entities a parent has, afaik it should be handled automatically(though having that list of child entities might be useful for certain situations).
     
    addent likes this.
  9. addent

    addent

    Joined:
    Apr 27, 2019
    Posts:
    18
    Thanks for the info!