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

Is it possible to have a Dynamicbuffer of Icomponent tags which can be set as components?

Discussion in 'Entity Component System' started by calabi, Jul 11, 2019.

  1. calabi

    calabi

    Joined:
    Oct 29, 2009
    Posts:
    232
    I've tried to do this but I'm not sure if I'm doing it right or whether its possible. I'm guessing it isn't possible because a dynamicbuffer is attached to an entity, I cant figure out how to access and add that as an component from that entity.

    Or maybe this isn't a good way to do what I want. I figured I could have it dynamically create 500 or so component tags and add them to core entities and then add that component tag to all the surrounding entity's that are within a certain distant. A sort of quick way to have a list of entities that are with a certain distance. I'm not sure if I've explained it well enough but that's the gist of it.
     
  2. Abbrew

    Abbrew

    Joined:
    Jan 1, 2018
    Posts:
    417
    I've done something similar. Here's the code if it helps. Explanation is below the code.

    Code (CSharp):
    1.  
    2. public class AllyProximitySystem : JobComponentSystem
    3. {
    4.     private EntityQuery dalmatianProximityUsers;
    5.     private EntityQuery epiroteProximityUsers;
    6.  
    7.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    8.     {
    9.         var awaredAlliesFromEntity =
    10.             GetBufferFromEntity<AllyWithinAwarenessRangeElement>(false);
    11.         var speakingAlliesFromEntity =
    12.             GetBufferFromEntity<AllyWithinSpeakingRangeElement>(false);
    13.  
    14.         var bodyHandles = new NativeArray<JobHandle>(4, Allocator.Temp);
    15.         var dalmatianAlliesTransforms =
    16.             dalmatianProximityUsers.ToComponentDataArray<LocalToWorld>(
    17.                 Allocator.TempJob,
    18.                 out var dalmatianAlliesTransformsJobHandle
    19.             );
    20.         var dalmatianAlliesEntities =
    21.             dalmatianProximityUsers.ToEntityArray(
    22.                 Allocator.TempJob,
    23.                 out var dalmatianAlliesEntitiesJobHandle
    24.             );
    25.         var epiroteAlliesTransforms =
    26.             epiroteProximityUsers.ToComponentDataArray<LocalToWorld>(
    27.                 Allocator.TempJob,
    28.                 out var epiroteAlliesTransformsJobHandle
    29.             );
    30.         var epiroteAlliesEntities =
    31.             dalmatianProximityUsers.ToEntityArray(
    32.                 Allocator.TempJob,
    33.                 out var epiroteAlliesEntitiesJobHandle
    34.             );
    35.  
    36.         bodyHandles[0] = dalmatianAlliesTransformsJobHandle;
    37.         bodyHandles[1] = dalmatianAlliesEntitiesJobHandle;
    38.         bodyHandles[2] = epiroteAlliesEntitiesJobHandle;
    39.         bodyHandles[3] = epiroteAlliesTransformsJobHandle;
    40.         inputDeps = JobHandle.CombineDependencies(
    41.             JobHandle.CombineDependencies(bodyHandles), inputDeps
    42.         );
    43.         bodyHandles.Dispose();
    44.  
    45.         inputDeps = new WithinRangeJob
    46.         {
    47.             alliesTransforms = dalmatianAlliesTransforms,
    48.             alliesEntities = dalmatianAlliesEntities,
    49.             awaredAlliesFromEntity = awaredAlliesFromEntity,
    50.             speakingAlliesFromEntity = speakingAlliesFromEntity
    51.         }.ScheduleSingle(dalmatianProximityUsers, inputDeps);
    52.         inputDeps = new WithinRangeJob
    53.         {
    54.             alliesTransforms = epiroteAlliesTransforms,
    55.             alliesEntities = epiroteAlliesEntities,
    56.             awaredAlliesFromEntity = awaredAlliesFromEntity,
    57.             speakingAlliesFromEntity = speakingAlliesFromEntity
    58.         }.ScheduleSingle(epiroteProximityUsers, inputDeps);
    59.  
    60.         return inputDeps;
    61.     }
    62.  
    63.    [BurstCompile]
    64.     private struct WithinRangeJob : IJobForEachWithEntity<LocalToWorld, AllyProximity>
    65.     {
    66.         [ReadOnly]
    67.         [DeallocateOnJobCompletion]
    68.         public NativeArray<LocalToWorld> alliesTransforms;
    69.         [ReadOnly]
    70.         [DeallocateOnJobCompletion]
    71.         public NativeArray<Entity> alliesEntities;
    72.  
    73.         [NativeDisableParallelForRestriction]
    74.         public BufferFromEntity<AllyWithinAwarenessRangeElement> awaredAlliesFromEntity;
    75.         [NativeDisableParallelForRestriction]
    76.         public BufferFromEntity<AllyWithinSpeakingRangeElement> speakingAlliesFromEntity;
    77.  
    78.         public void Execute(
    79.             Entity entity,
    80.             int jobIndex,
    81.             ref LocalToWorld transform,
    82.             ref AllyProximity proximityStats
    83.         )
    84.         {
    85.             var awaredAllies = awaredAlliesFromEntity[entity];
    86.             var awaredAlliesLength = awaredAllies.Length;
    87.             var awaredAlliesEntities =
    88.                 new NativeArray<Entity>(awaredAlliesLength,Allocator.Temp);
    89.             for (var i = 0; i < awaredAlliesLength; i++)
    90.             {
    91.                 awaredAlliesEntities[i] = awaredAllies[i].ally;
    92.             }
    93.  
    94.             var speakingAllies = speakingAlliesFromEntity[entity];
    95.             var speakingAlliesLength = speakingAllies.Length;
    96.             var speakingAlliesEntities =
    97.                 new NativeArray<Entity>(speakingAlliesLength, Allocator.Temp);
    98.             for (var i = 0; i < speakingAlliesLength; i++)
    99.             {
    100.                 speakingAlliesEntities[i] = speakingAllies[i].entity;
    101.             }
    102.  
    103.             var alliesTransformsLength = alliesTransforms.Length;
    104.             for(var i = 0; i < alliesTransformsLength; i++)
    105.             {
    106.                 var allyEntity = alliesEntities[i];
    107.                 var allyAwareness = awaredAlliesFromEntity[allyEntity];
    108.                 var allySpeaking = speakingAlliesFromEntity[allyEntity];
    109.  
    110.                 if (entity.Equals(allyEntity))
    111.                 {
    112.                     continue;
    113.                 }
    114.                 var allyTransform = alliesTransforms[i];
    115.                 var withinAwarenessRadius =
    116.                     allyTransform.Position.DistanceFrom(transform.Position)
    117.                     < proximityStats.awarenessRadius;
    118.                 var awarenessContainsThis =
    119.                     awaredAlliesEntities.Contains(allyEntity);
    120.                 if (withinAwarenessRadius
    121.                     && !awarenessContainsThis
    122.                 )
    123.                 {
    124.                     awaredAllies.Add(new AllyWithinAwarenessRangeElement
    125.                     {
    126.                         ally = allyEntity
    127.                     });
    128.                     allyAwareness.Add(new AllyWithinAwarenessRangeElement
    129.                     {
    130.                         ally = entity
    131.                     });
    132.                 }
    133.                 else if (!withinAwarenessRadius
    134.                     && awarenessContainsThis
    135.                 )
    136.                 {
    137.                     awaredAllies.Remove(new AllyWithinAwarenessRangeElement
    138.                     {
    139.                         ally = allyEntity
    140.                     });
    141.                     allyAwareness.Remove(new AllyWithinAwarenessRangeElement
    142.                     {
    143.                         ally = entity
    144.                     });
    145.                 }
    146.  
    147.                 var withinSpeakingRadius =
    148.                     allyTransform.Position.DistanceFrom(transform.Position)
    149.                     < proximityStats.speakingRadius;
    150.                 var speakingContainsThis =
    151.                     speakingAlliesEntities.Contains(allyEntity);
    152.                 if (withinSpeakingRadius
    153.                     && !speakingContainsThis
    154.                 )
    155.                 {
    156.                     speakingAllies.Add(new AllyWithinSpeakingRangeElement
    157.                     {
    158.                         entity = allyEntity
    159.                     });
    160.                     allySpeaking.Add(new AllyWithinSpeakingRangeElement
    161.                     {
    162.                         entity = entity
    163.                     });
    164.                 }
    165.                 else if (!withinSpeakingRadius
    166.                     && speakingContainsThis
    167.                 )
    168.                 {
    169.                     speakingAllies.Remove(new AllyWithinSpeakingRangeElement
    170.                     {
    171.                         entity = allyEntity
    172.                     });
    173.                     allySpeaking.Remove(new AllyWithinSpeakingRangeElement
    174.                     {
    175.                         entity = entity
    176.                     });
    177.                 }
    178.             }
    179.         }
    180.     }
    181.  
    182.     protected override void OnCreate()
    183.     {
    184.         dalmatianProximityUsers = GetEntityQuery(new EntityQueryDesc
    185.         {
    186.             All = new ComponentType[]
    187.             {
    188.                 ComponentType.ReadOnly<DalmatianTag>(),
    189.                 ComponentType.ReadOnly<AllyProximity>(),
    190.                 ComponentType.ReadOnly<LocalToWorld>(),
    191.                 ComponentType.ReadOnly<Translation>()
    192.             },
    193.         });
    194.         dalmatianProximityUsers.SetFilterChanged(typeof(Translation));
    195.  
    196.         epiroteProximityUsers = GetEntityQuery(new EntityQueryDesc
    197.         {
    198.             All = new ComponentType[]
    199.             {
    200.                 ComponentType.ReadOnly<EpiroteTag>(),
    201.                 ComponentType.ReadOnly<AllyProximity>(),
    202.                 ComponentType.ReadOnly<LocalToWorld>(),
    203.                 ComponentType.ReadOnly<Translation>()
    204.             },
    205.         });
    206.         epiroteProximityUsers.SetFilterChanged(typeof(Translation));
    207.     }
    208. }
    209.  
    You set the change filter on Translation, because Unity's TRSToLocalToWorldSystem constantly writes Translation to LocalToWorld, but Translation is written to only if one of your systems do. This way the system only activates when an entity moves. Once it does it checks all other "allied" entities to see if they're still within range, and update the buffer of allied entities accordingly. Your use case is different since you only want "core entities" to detect within range entities, so modify the system above to have two entity queries - one for core entities, and one for within range entities. The job would then cycle through core entities and alliesTransforms and alliesEntities would be those of your non-core entities.

    I understand that keeping track of entities within range of another entity is still extra work, but it reduces code overhead and decouples systems that rely on entities within range from systems that maintain entities within range. You'd only have to have a BufferFromEntity<WithinRangeAllyElement> in the depending system instead of calculating all allies within range every frame.
     
    tarahugger likes this.
  3. calabi

    calabi

    Joined:
    Oct 29, 2009
    Posts:
    232
    Wow, that's great, thanks. It will take me a bit to parse that code as I'm still trying to figure out how exactly jobcomponentsystems work to be honest, the docs and examples arent that much help and very few tutorials exist. But I guess that's what you get when you try using something that is still in early development, thanks again.