Search Unity

Need help to understand DynamicBuffer

Discussion in 'Entity Component System' started by strexet, Nov 24, 2018.

  1. strexet

    strexet

    Joined:
    Sep 30, 2016
    Posts:
    5
    Hello,
    In my game I have a relationship where one parent has many children.
    I need to access children's entities from parent entity.
    I've heard that DynamicBuffer can solve my problem, but I can't understand how it works:(

    I googled as hard as I can to find basic examples of implementing DynamicBuffer, but failed...

    I'll really appreciate if someone could guide me, maybe throw some simple examples in this thread.

    The best thing would be an implementation of parend-children relationship with comments and explanations (yeah, I'm a dreamer).
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
  3. strexet

    strexet

    Joined:
    Sep 30, 2016
    Posts:
    5
    And where do I add buffer, to the parent, I suppose? Child is wrong target for this, as I understand...
    It all make sense if the DynamicBuffer behaves just like a normal array...
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,779
    Technically there is no sense of child and parent when using buffer with entities.
    You just need store relevant indexes of entities in buffer, to reference root / children.

    This have been ask few times here already.
    For example simply searching forum keyword "parent"
    https://forum.unity.com/search/33740257/?q=parent&t=post&o=date&c[node]=147

    https://forum.unity.com/threads/pat...-with-groups-of-children.584851/#post-3904030

    And some example of using DynamicBuffer
    [Example] IJobProcessComponentDataWithEntity and IBufferElementData
     
  5. Piefayth

    Piefayth

    Joined:
    Feb 7, 2017
    Posts:
    61
    Thought I'd chime in since my question got linked above. I actually ended up refactoring out buffers entirely for this pattern. If order of children doesn't matter, you can just create a SharedComponentData component type for your parent and, for each parent, attach the same instance of this SCD to each child.

    You can then trivially iterate all children and get a reference to the parent component. The shared component data array in the below code contains one index for each child that points to the data for the correct parent.

    Code (CSharp):
    1. ComponentGroup childrenGroup = entityManager.CreateComponentGroup(typeof(Child), typeof(Parent));
    2. SharedComponentDataArray<Parent> childParents = childrenGroup.GetSharedComponentData<Parent>();
    Then you can store a NativeArray<Entity> of children on the parent component. By storing the appropriate index (based on your order) on the child, you can have the child insert itself into the parent's entity array of children.

    Code (CSharp):
    1. public void Execute(int jobIndex) {
    2.     NativeArray<Entity> childStorage = childParents[jobIndex].children;
    3.     childStorage[childComponents[jobIndex].index] = childEntities[jobIndex];
    4. }
    Often, as a result of using this pattern, you'll want to schedule a job on a per-parent basis. That is, "for each parent, schedule a job that iterates every child of that parent." A pattern exists for that.

    Code (CSharp):
    1. List<Parent> knownParents;
    2. entityManager.GetAllUniqueSharedComponentData(knownParents);
    3.  
    4. // index 0 is the "default" shared component, can skip
    5. for (int i = 1; i < knownParents.Count; i++) {
    6.     childGroup.SetFilter(knownParents[i]);
    7.     // now queries to this component group will only return children associated with the provided parent
    8.  
    9.     // all the same parent
    10.     SharedComponentDataArray<Parent> parents = childGroup.GetSharedComponentDataArray<Parent>();
    11.  
    12.     // all children of that parent
    13.     ComponentDataArray<Child> children = childGroup.GetComponentDataArray<Child>();
    14.  
    15.     // schedule some job
    16. }
    The above pattern is especially relevant once you realize that you cannot continually access the contents of the data arrays between job schedules. You need to create one per schedule, or to yank all the data out of them all at once, then schedule afterwards in a way that does not reference them directly.

    So, if you want to iterate all entities-per-parent in no particular order, you can use exactly the SetFilter pattern in the last code sample. If you want to iterate them in a specific order or with random access, you'll need to use a NativeArray<Entity> on your shared component, then fill it with the children however you need to. After it's populated correctly, you can just take the SetFilter pattern and iterate directly on the knownParents, as the NativeArray<Entity> of children will be available on the SharedComponentData written to your List<Parent>.
     
    Last edited: Nov 24, 2018
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Child/parent relationship not matter, and DB is “just array” in simple understanding.
     
    Last edited: Nov 25, 2018
    Antypodish likes this.