Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Access entity in ForEach?

Discussion in 'Entity Component System' started by gigamech, Feb 21, 2019.

  1. gigamech

    gigamech

    Joined:
    Mar 31, 2015
    Posts:
    23
    The new ForEach syntax is lovely, but is there a way to access entities using it? For example if you need to destroy an entity based on changes in a component it would be useful to do something like this:

    Code (CSharp):
    1. var commands = aBarrier.CreateCommandBuffer();
    2.  
    3. ForEach((ref Health health, ref Entity entity)=>
    4. {
    5.     health -= 1;
    6.     if (health <= 0) commands.DestroyEntity(entity);
    7. });
    Is there an equivalent way to do this aside from getting ComponentDataArrays and EntityArrays and iterating over them manually?
     
    Zagule likes this.
  2. gigamech

    gigamech

    Joined:
    Mar 31, 2015
    Posts:
    23
    I realized that I could check the decompiled code for ForEach and see all the overloads. There indeed is one for Entity and it looks like this (it's just like the one above but the entity comes first):

    Code (CSharp):
    1. ForEach((Entity e, ref MyComponent c)=> /*do something*/);
     
    Zagule likes this.
  3. digitaliliad

    digitaliliad

    Joined:
    Jul 1, 2018
    Posts:
    64
    ForEach((Entity e, ref MyComponent c) => { /*do something*/ }, MyComponentGroup);


    There's also this, which would let you filter by group, so you could control which entities you want to process by tag, or whatever, instead of processing all entities with MyComponentType.
     
  4. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Do i need to declare my group sth. special ??
    Does not seem to work as normal ?!?
     
  5. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    I don't know what version of Entities you're using but ForEach has changed since then. New way is
    Code (CSharp):
    1. Entities.With(EntityQuery).ForEach( (Entity e, ref MyComponent c) => { /*do something*/ });
    where EntityQuery is the new name for ComponentGroup.
     
  6. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    I cannot do hybrid component system with monobehaviour any more, not ?
    What if i would like to access a particle system ??

    I am on latest version
     
  7. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    Yes you can still use hybrid components with ForEach.
    Entities.With(query).ForEach( (Entity entity, UnityEngine.ParticleSystem particleSystem)
     
    Held0fTheWelt likes this.
  8. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Is there something, i could inform more about, what changes to what ?
    I cannot see those things ...
    Lately i am looking, where ScaleProxy went to.
     
  9. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    It is now NonUniformScaleProxy
     
  10. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Lately:

    I don't know anything about "EntityQuery" query yet.
    It seems to be the group, but as i said:
    It's not just putting in the groups struct.

    Is there a resource other than the github samples, where i can read about, what changed and how it changed ?
     
  11. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I think the best place to track changes so far is here in the forum.
    Also Entities package has now a proper documentation
     
    Last edited: Apr 7, 2019
    Held0fTheWelt likes this.
  12. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Code (CSharp):
    1.         Entities.ForEach((Entity spaceShip, ref SpaceshipIdentifier ident, ref Translation shipPosition, ref Rotation shipRotation) => {
    2.             Entities.ForEach((Entity asteroid, ref AsteroidForce asteroidForce, ref Translation position) => {
    3.                 float3 difference = position.Value - shipPosition->Value;
    4.                 if (sqrMagnitudeLimit >= math.lengthsq(difference))
    5.                 {
    6.                     float calc = (math.lengthsq(difference) / sqrMagnitudeLimit) / 2;
    7.  
    8.                     difference = math.normalize(difference);
    9.  
    10.                     difference *= new float3(calc, calc, calc);
    11.  
    12.                     calculationList.Add(difference);
    13.  
    14.                 }
    15.             });          
    16.         });
    And i cannot access my shipPosition ?!?
    This is all totally away from what it was before, lambda back and forth ...
     
  13. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Ah. used a pointer before, idiot me.
    And obviously i don't want to cycle through the asteroid entities that often, as i only need their positions !

    Code (CSharp):
    1.  Entities.ForEach((Entity asteroid, ref AsteroidForce asteroidForce, ref Translation asteroidPosition) => {
    2.             asteroidPositions.Add(asteroidPosition.Value);
    3.         });
    4.  
    5.         float sqrMagnitudeLimit = Radar.RadarRange * Radar.RadarRange;
    6.  
    7.         Entities.ForEach((Entity spaceShip, ref SpaceshipIdentifier ident, ref Translation shipPosition, ref Rotation shipRotation) => {
    8.             for (int i = 0; i < asteroidPositions.Count; i++)
    9.             {          
    10.                 float3 difference = asteroidPositions[i]- shipPosition.Value;
    11.                 if (sqrMagnitudeLimit >= math.lengthsq(difference))
    12.                 {
    13.                     float calc = (math.lengthsq(difference) / sqrMagnitudeLimit) / 2;
    14.  
    15.                     difference = math.normalize(difference);
    16.  
    17.                     difference *= new float3(calc, calc, calc);
    18.  
    19.                     calculationList.Add(difference);
    20.  
    21.                 }
    22.             }
    23.         });
    That's looking a bit better.
     
  14. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Thank you !
    I think, i am back on track in updating my code !

    But i still don't get, where i get the Querytype from.
    It seems to work without.
     
    Last edited: Apr 7, 2019
  15. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Code (CSharp):
    1. Entities.ForEach((Entity e, ref ThrustInputController inputController, ref ThrustForce force, Rigidbody rigidbody) => {
    2.             /*do something*/
    3.         });
    And this isn't allowed, too ???
    As i am preparing to move over to pure as much, as i can, i started to use the structs, rather than the proxies, doing this, worked since here quite well:

    Code (CSharp):
    1.     unsafe public struct ThrustSystemGroup
    2.     {
    3.         public Transform Transform;
    4.         public Rigidbody Rigidbody;
    5.         public ThrustInputController* ThrustInputController;
    6.         public ThrustForce* ThrustForce;
    7.     }
    But it looks, i cannot mix them together again, now ?!?

    Yes, i could access the proxies via the Value, but why should i ?!?
     
  16. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Somehow, this has to do with order !?!?

    This here is working well !

    Code (CSharp):
    1.         Entities.ForEach((Entity e, Rigidbody rigidbody, ref ThrustInputController inputController, ref ThrustForce force) => {
    2.             /*do something*/
    3.         });
     
  17. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    Simplest way would be to make a JobComponentSystem, and in that system do a
    IJobForEachWithEntity


    Code (CSharp):
    1.     public struct HealthJob : IJobForEachWithEntity<Health>
    2.     {
    3.         [ReadOnly] public EntityCommandBuffer.Concurrent CommandBuffer;
    4.  
    5.         public void Execute(Entity entity, int index, ref Health h)
    6.         {
    7.             h.value -= 1;
    8.             if (h.value <= 0)
    9.                 CommandBuffer.DestroyEntity(entity);
    10.         }
    11.     }
     
    Held0fTheWelt likes this.
  18. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    Yes. ForEach is made of a bunch of generated delegates of the form F_EDBC for E=Entity, D=IComponentData, B=DynamicBuffer and C=Class.
    You can find them all in EntityQueryBuilder_ForEach.gen.cs in PackageCache folder.
    The type and order of parameters must match one of these.

    Do you mean EntityQuery? It's a direct replacement of ComponentGroup. Use GetEntityQuery() instead of GetComponentGroup() just like before.
    Then you can use
    Entities.With(entityQuery).ForEach(...)
    However if you don't create your own query, the ForEach will create one for you based on the parameters.

    That doesn't work with hybrid components which is what he's using with Rigidbody.
     
    Init33 likes this.
  19. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    My Bad, didn't see the hybrid part.
     
  20. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    173
    Now i understand that !