Search Unity

(Solved) Unable to get Entities.ForEach( ) examples working

Discussion in 'Entity Component System' started by NickVst, Jun 7, 2019.

  1. NickVst

    NickVst

    Joined:
    Feb 17, 2017
    Posts:
    25
    I'm at a loss here.

    I want to move multiple entities that all contain a set of components, in this case PlayerInput and Speed. If an entity has both of these components, I want to be able to move them around.

    So, for this I create a MovementSystem class.

    Code (CSharp):
    1. public class PlayerMovementSystem : ComponentSystem
    2. {
    3.     private struct Group
    4.     {
    5.         public Transform transform;
    6.         public PlayerInput playerInput;
    7.         public Speed speed;
    8.     }
    9.  
    10.     protected override void OnUpdate()
    11.     {
    12.         Entities.WithAll<Group>().ForEach((entity) => {
    13.             // Do stuff here
    14.         }
    15.     }
    16. }
    However, the entity does not have a Group here, nor does it have any of the members that Group contains.

    So, I change the method to this instead, which Unity has samples for on their github aswell.

    Code (CSharp):
    1. Entities.ForEach((ref Transform transform, ref PlayerInput playerInput, ref Speed speed) => { /*stuff*/ });
    However, VS doesn't like this.

    Parameter 1 is declared as type 'ref PlayerInput' but should be 'Unity.Entities.Entity' 


    But as I learnt before, doing it that way means my Entity does not have the proper items in it.

    If I just put the entity as first item in the lambda parameters, I get

    Delegate 'EntityQueryBuilder.F_E' does not take 2 arguments 


    So I don't know how to use the ForEach method to get all Entities with a component or set of components. Most other materials I found on it use the InjectAttribute. but that's been deprecated and will no longer work.
     
  2. psuong

    psuong

    Joined:
    Jun 11, 2014
    Posts:
    126
    For Entities.WithAll(), you pass the ComponentTypes into the params.

    Code (CSharp):
    1. // By using Entities.WithAll<Group> you looking for all Entities which happen
    2. // to have an archetype of types: Group. This isn't valid because this is a local
    3. // structure which needs to be added to an entity.
    4.  
    5.     private struct Group
    6.     {
    7.         public Transform transform;
    8.         public PlayerInput playerInput;
    9.         public Speed speed;
    10.     }
    You have a few of options for a ComponentSystem:

    1. using an EntityQuery and Entities.With()
    Code (CSharp):
    1.  
    2. public class AComponentSystem : ComponentSystem {
    3.   EntityQuery aUniqueQuery;
    4.   protected override void OnCreate() {
    5.     // I am assuming that PlayerInputs and Speed are structs with IComponentData
    6.     aUniqueQuery = GetEntityQuery(typeof(Transform), typeof(PlayerInput), typeof(Speed));
    7.   }
    8.  
    9.   protected override void OnUpdate() {
    10.     // We follow the F_CDD delegate
    11.     Entities.With(aUniqueQuery).ForEach(Transform transform, ref PlayerInputs inputs, ref Speed speed) => {});
    12.   }
    13. }
    14.  
    2. What you posted which is just using Entities.ForEach

    Code (CSharp):
    1.  
    2. public class AComponentSystem : ComponentSystem {
    3.  
    4.   protected override void OnUpdate() {
    5.     // We follow the F_CDD delegate
    6.     Entities.ForEach(Transform transform, ref PlayerInputs inputs, ref Speed speed) => {});
    7.   }
    8. }
    9.  
    3. Enitites.WithAll<>().ForEach

    Code (CSharp):
    1.  
    2. public class AComponentSystem : ComponentSystem {
    3.  
    4.   protected override void OnUpdate() {
    5.     // We follow the F_CDD delegate
    6.     Entities.WithAll<Transform, PlayerInputs, Speed>().ForEach(Transform transform, ref PlayerInputs inputs, ref Speed speed) => {});
    7.   }
    8. }
    9.  

    If you look at the ForEach in Visual Studio, you'll see a lot of delegate patterns you can pass into the Entities.ForEach() iterator.

    C - stands for class
    D - stands for ComponentData (a struct which implements IComponentData)
    S - stands for SharedComponentData (a struct which implements ISharedComponentData)
    B - stands for BufferElementData (a struct which implements IBufferElementData)
    E - stands for Entity

    All ComponentDatas are accessed via ref keywords as you need a reference to them.
     
  3. NickVst

    NickVst

    Joined:
    Feb 17, 2017
    Posts:
    25
    EDIT: Urgh. Made a classic beginner's mistake. I didn't check to see if I changed the IComponentData classes to structs.

    After I had done so, the delegates stopped spitting out errors. Thank you very much for your help.


    Thank you for responding.

    Unfortunately, none of the examples you have presented work for me. All of them fail at the same point, that is, the ForEach gives the same error as above.

    Delegate 'EntityQueryBuilder.F_E' does not take 3 arguments


    So I checked the declaration of the delegate method in the EntityQueryBuilder class. I searched for ForEach(F_ in this class, which should represent all delegate methods. However, there is only one method that corresponds to this pattern in this file.

            public void ForEach(F_E action);


    I should have mentioned this before, but the versions I use are:

    Unity: 2019.1.5f1
    Entities package: preview.33 - 0.0.12

    Perhaps an update to one of these packages made the previous method obsolete. but I cannot prove that theory anywhere.
     
    Last edited: Jun 9, 2019
    MNNoxMortem and psuong like this.
  4. psuong

    psuong

    Joined:
    Jun 11, 2014
    Posts:
    126
    Np, glad you got it working :)