Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Entities.With() : Proper way to access Components?

Discussion in 'Entity Component System' started by pakfront, Jun 16, 2019.

  1. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    The docs and package test code don't actually have an example of accessing and modifying component data in a ComponentSystem using Entities.With(). They just have
    //do stuff


    I'm using an exiting EntityQuery.

    Do I just use EntityManager.Get/SetComponentData() or is there a better/more efficient way?

    I realize that ComponentSystem is not efficient, but I have a small number of entities to iterate over and only once in a while. The problem is a bit a hard to parallelize 'til I prototype it, so this seemed a simple way to get it working.

    Current simplified version for example only:
    Code (CSharp):
    1.         protected override void OnUpdate()
    2.         {
    3.             Entities.With(allRootsGroup).ForEach((Entity entity) =>
    4.             {
    5.                 // Debug.Log("Root "+entity);
    6.                 if (EntityManager.HasComponent<PlayerInput>(entity))
    7.                 {
    8.                     var order = EntityManager.GetComponentData<PlayerInput>(entity);
    9.                     //more complex stuff happens here
    10.                     EntityManager.SetComponentData(entity, new Goal
    11.                     {
    12.                         Value = order.Goal
    13.                     });
    14.                 }
    15.                 else {
    16.                   // do other stuff
    17.                 }
    18.             });
    19.         }
     
    Last edited: Jun 16, 2019
  2. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    Ah, I can use generics, though I don't know if this is much faster.Also I cant; use Buffers as args i the lambda.
    Code (CSharp):
    1.         protected override void OnUpdate()
    2.         {
    3.             Entities.With(allRootsGroup).ForEach<Goal>((Entity entity, ref Goal goal) =>
    4.             {
    5.                  var children = EntityManager.GetBuffer<MyChild>(entity);
    6.  
    7.                 // Debug.Log("Root "+entity);
    8.                 if (EntityManager.HasComponent<PlayerInput>(entity))
    9.                 {
    10.                     var order = EntityManager.GetComponentData<PlayerInput>(entity);
    11.                     goal.Value = order.Goal;
    12.                 } else {
    13.                   // do other stuff
    14.                 }
    15.             });
    16.         }
     
    Last edited: Jun 16, 2019
  3. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    In your first example it would be as easy as this:
    Code (CSharp):
    1.     Entities.With(allRootsGroup).ForEach((ref PlayerInput input, ref Goal goal) =>
    2.     {
    3.       goal.Value = input.Goal;
    4.     });
     
  4. Guerro323

    Guerro323

    Joined:
    Sep 2, 2014
    Posts:
    25
    This code would only work if you are sure PlayerInput is on all entities of the group.
    The reason he use With() (and that he check if there is a PlayerInput component) instead of WithAll() is that some components can be present or not, if he access to a component that is not present on an entity, he can have a nullref exception.
     
  5. Guerro323

    Guerro323

    Joined:
    Sep 2, 2014
    Posts:
    25
    You can use buffers in ForEach:
    Code (CSharp):
    1.  
    2. Entities.WithAll(allRootsGroup).ForEach((Entity entity, DynamicBuffer<MyChild> children, ref Goal goal) =>
    3. {
    4.     // your stuff
    5. });
    6.  
     
    pakfront likes this.
  6. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I've missed that possibility.
    In that case you can use:
    Code (CSharp):
    1.     Entities.With(allRootsGroup).ForEach((ref PlayerInput input, ref Goal goal) => {
    2.       if(UnsafeUtility.AddressOf(ref input) != null && UnsafeUtility.AddressOf(ref goal) != null)
    3.         goal.Value = input.Goal;
    4.     });
     
    Last edited: Jun 17, 2019
    pakfront likes this.