Search Unity

Create Component with referenced Entity

Discussion in 'Entity Component System' started by Spy-Shifty, Jun 14, 2018.

  1. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Hi,

    I've the following situation:

    I need to create an Entity and hold the entity in an EntityReference Component of an other entity.
    Now this is done in one step.

    Problem is I can't use PostUpdateCommand to create the entity because I won't get an Entity back.
    So I created an EntityFactoryWorld with its own EntityManager.
    And at some point I move my entities from the EntityFactoryWorld to my normal world

    But what happens with the Entity in the EntityReferenceComponent?
    As I imagine, I won't be able to find the entity anymore?

    How to solve this problem?

    Code (CSharp):
    1. struct EntityReference : IComponentData {
    2.       public Entity value;
    3. }
    4.  
    5. //...
    6. void Foo() {
    7.      Entity otherEntity = EntityFactory.CreateSomeEntity();
    8.      PostUpdateCommand.AddComponent(entities[i], new EntityReference { value = otherEntity });
    9. }
    10.  
    11.  
     
  2. zulfajuniadi

    zulfajuniadi

    Joined:
    Nov 18, 2017
    Posts:
    117
    PostUpdateCommand is good to defer the command to post update. If you need instant access the values you can always use EntityManager.CreateEntity.
     
  3. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Well, but this will create a hard sync point.
     
  4. zulfajuniadi

    zulfajuniadi

    Joined:
    Nov 18, 2017
    Posts:
    117
    Well yeah, that is one of the side effect. One way to reduce the effect is pushing the system to the very end of the frame:

    using UnityEngine.Experimental.PlayerLoop;

    [UpdateAfter (typeof (PostLateUpdate))]
     
  5. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Well that's not a solution for me :/

    It would invalidate my current system... (need to create entity with ComponentType.FixedArray)
    One more thing is that this doesn't work well on a more complex scenario...
     
  6. zulfajuniadi

    zulfajuniadi

    Joined:
    Nov 18, 2017
    Posts:
    117
    Sync points are to be expected I guess. Just not too many of them in one frame. I did just end up using EntityManager.CreateEntity. It's quite performant. I could spawn like 10,000 entities on the main thread in around 100ms. Of course this doesn't happen every frame.
     
  7. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    you could do a 2-steps thing:
    Code (CSharp):
    1. public class InverseEntityReference : IComponentData {Entity value;}
    2.  
    3. // step 1: create entity
    4. PostUpdateCommands.CreateEntity(archetype);
    5. PostUpdateCommends.AddComponent(new InverseEntityReference {value = oldEntity});
    6.  
    7. //step 2: invert references system
    8. struct Group {
    9.     public ComponentDataArray<InverseEntityReference> references;
    10.     public EntityArray entities;
    11. }
    12. OnUpdate loop: {
    13.     PostUpdateCommands.AddComponent (group.references[i].value, new EntityReference{value = group.entities[i]});
    14.     PostUpdateCommands.RemoveComponent<InverseEntityReference>(group.entities[i])
    15. }
     
    Spy-Shifty likes this.
  8. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Hi, thank you for the answer! I made it the way you described it.
    I've used 2 systems one for creating the entity and another that runs after the first one to assign the correct relations.