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

Accessing zero-length (tag) components using Entities.ForEach

Discussion in 'Entity Component System' started by Marble, Dec 7, 2019.

  1. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    I'm testing out the different ways of querying entities and am learning about some of the patterns that current ECS users are using. I'm attracted to the idea of using tag components with no data to better group my entities. I'm also interested in the new ForEach lambda, but when I use it to make a query that includes tag components, I see runtime exceptions. Tags work all right in IJobForEach.

    I understand that ForEach generates high-efficiency boilerplate, and that this may be what precludes using a tag in one. However, I wanted to double check to see whether:

    1) There is a convenient way to use tags with ForEach that I'm missing, since I'm just starting to learn ECS conventions.

    2) If not, whether the ForEach codegen eventually will accommodate zero-length components.

    Here is the ForEach that throws exceptions:
    Code (CSharp):
    1. public class TagSystem_ForEach : JobComponentSystem {
    2.    
    3.     protected override JobHandle OnUpdate( JobHandle inputDependencies ) {
    4.         float deltaTime = Time.DeltaTime;
    5.        
    6.         var jobHandle = Entities.ForEach( (
    7.                ref Translation translation,
    8.                in Player playerTag
    9.             ) => {
    10.                 translation.Value = new float3( translation.Value.x + deltaTime, translation.Value.y, translation.Value.z );
    11.             }
    12.         ).Schedule( inputDependencies );
    13.        
    14.         return jobHandle;
    15.     }
    16. }
    Here is the IJobForEach that doesn't.
    Code (CSharp):
    1. public class TagSystem : JobComponentSystem {
    2.    
    3.     [BurstCompile]
    4.     struct TagSystemJob : IJobForEach<Translation, Player> {
    5.         public float deltaTime;
    6.        
    7.         public void Execute( ref Translation translation, [ReadOnly] ref Player playerTag ) {
    8.             translation.Value = new float3( translation.Value.x + deltaTime, translation.Value.y, translation.Value.z );
    9.         }
    10.     }
    11.    
    12.     protected override JobHandle OnUpdate( JobHandle inputDependencies ) {
    13.        
    14.         var job = new TagSystemJob { deltaTime = Time.DeltaTime };
    15.         return job.Schedule( this, inputDependencies );
    16.     }
    17. }
    The exception is:
    Code (CSharp):
    1. System.ArgumentException: ArchetypeChunk.GetNativeArray<{0}> cannot be called on zero-sized IComponentData
     
  2. TRS6123

    TRS6123

    Joined:
    May 16, 2015
    Posts:
    246
    Include tag components via WithAll instead of ForEach:
    Code (CSharp):
    1. var jobHandle = Entities.WithAll<PlayerTag>().ForEach( (
    2.            ref Translation translation
    3.         ) => {
    4.             translation.Value = new float3( translation.Value.x + deltaTime, translation.Value.y, translation.Value.z );
    5.         }
    6.     ).Schedule( inputDependencies );
     
  3. vildauget

    vildauget

    Joined:
    Mar 10, 2014
    Posts:
    120
    Code (CSharp):
    1. JobHandle jobHandleForEach = Entities
    2.                 // filters are used for components that won't be used in job for read/write (thos are parameters)
    3.                 .WithName("foreach_inline_job")                                             // name of the job in debugger
    4.                 .WithNone<MyAtomData2>()                                                    // filter out any Entities with the component
    5.                 .WithAny<MyAtomData4, MyAtomData5>()                                        // require either component for entity to be included in filter
    6.                 .WithAll<MyAtomData6, MyAtomData7>()                                        // require all components for entity to be included in filter
    7.                 .WithEntityQueryOptions(EntityQueryOptions.IncludeDisabled)                 // include entities with the special Disabled component
    8.                 .WithBurst(FloatMode.Default, FloatPrecision.Standard, false)               // burst settings (set true for synchronous mode)
    9.                 .ForEach((Entity entity, int entityInQueryIndex, in MyAtomData3 myAtomData3) =>  // Entity entity = currently passed entity, entityInQueryIndex = the current index of the array of entities passed in, in = read only, ref = write
    10.              
    11.                 {
     
    jdtec, Onigiri and mkracik like this.
  4. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    Great! Thanks for the help.
     
  5. Lucas-Meijer

    Lucas-Meijer

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    175
    hey Marble, thanks for the report! as others mention here, you can use .WithAll<>(), but what you were doing makes total sense, and we should just make that work, or at the very least give you a 10x better error message.