Search Unity

How to batch changes to entities

Discussion in 'Entity Component System' started by Deleted User, Dec 27, 2018.

  1. Deleted User

    Deleted User

    Guest

    Hey,

    the thread title is pretty generic but i couldn't find a better title.

    I try to implement that one entity can damage another entity. My current thinking is the following flow:

    Code (CSharp):
    1. public struct PhysicalDamage : IComponentData
    2. {
    3.     public uint Value;
    4. }
    5.  
    6. public struct Target : IComponentData
    7. {
    8.     public Entity Entity;
    9. }
    10.  
    11. public struct PhysicalDamageReceived : IComponentData
    12. {
    13.     public uint Value;
    14. }
    Entity A has component PhysicalDamage. When it should damage another entity it gets added a Target component with Entity B as Value. Than a system should add all damage that Entity B takes on to component PhysicalDamageReceived. Entity B might have PhysicalDamageReceived already but that shouldn't matter. It should work either way.

    My current (not working) solution looks like this:
    Code (CSharp):
    1. public class DealPhysicalDamageMain : ComponentSystem
    2. {
    3.     private ComponentGroup _group;
    4.  
    5.     protected override void OnCreateManager()
    6.     {
    7.         base.OnCreateManager();
    8.         _group = GetComponentGroup(
    9.             new ECSQueryBuilder2().RequireReadOnly<PhysicalDamage>()
    10.                                   .RequireReadOnly<Target>()
    11.                                   .Build()
    12.         );
    13.     }
    14.  
    15.     protected override void OnUpdate()
    16.     {
    17.         var physicalDamageType = GetArchetypeChunkComponentType<PhysicalDamage>(true);
    18.         var targetType = GetArchetypeChunkComponentType<Target>(true);
    19.  
    20.         var chunks = _group.CreateArchetypeChunkArray(Allocator.Temp);
    21.         for(var i = 0; i < chunks.Length; ++i)
    22.         {
    23.             var chunk = chunks[i];
    24.             var physicalDamages = chunk.GetNativeArray(physicalDamageType);
    25.             var targets = chunk.GetNativeArray(targetType);
    26.             for(var j = 0; j < chunk.Count; ++j)
    27.             {
    28.                 var damage = physicalDamages[i].Value;
    29.                 var target = targets[i].Entity;
    30.  
    31.                 if(EntityManager.HasComponent<PhysicalDamageReceived>(target))
    32.                 {
    33.                     var physicalDamageReceived = EntityManager.GetComponentData<PhysicalDamageReceived>(target);
    34.                     physicalDamageReceived.Value += damage;
    35.  
    36.                     EntityManager.SetComponentData(target, physicalDamageReceived);
    37.                 }
    38.                 else
    39.                 {
    40.                     EntityManager.AddComponentData(target, new PhysicalDamageReceived { Value = damage });
    41.                 }
    42.             }
    43.         }
    44.     }
    45. }
    I first started with a job version but that made thinks not either. I have no idea how i could collapse the NativeMultiHashMap<Entity, uint>.

    Code (CSharp):
    1. public class DealPhysicalDamage : JobComponentSystem
    2. {
    3.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    4.     {
    5.         var map = new NativeMultiHashMap<Entity, uint>();
    6.         var mapDamage = new MapPhysicalDamage
    7.         {
    8.             Map = map.ToConcurrent()
    9.         };
    10.  
    11.         return mapDamage.Schedule(this, inputDeps);
    12.     }
    13.  
    14.     private struct MapPhysicalDamage : IJobProcessComponentData<PhysicalDamage, Target>
    15.     {
    16.         public NativeMultiHashMap<Entity, uint>.Concurrent Map;
    17.         public void Execute(ref PhysicalDamage data0, ref Target data1)
    18.         {
    19.             Map.Add(data1.Entity, data0.Value);
    20.         }
    21.     }
    22. }
    I'm out of ideas. It might be that i'm stuck somewhere with my thinking and try to do it the wrong way.
    If anyone has an idea how i can get to where i want to be that would be helpful.

    Thanks and regards,
    sgrueling
     
  2. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Hi sorry for the short answer... I'm on the run...

    Please search the forum for event system. Your topic was discussed many times in the forum!
     
  3. Deleted User

    Deleted User

    Guest

    Thanks for the response. :)

    I did extensive searching and i think that i have a good grasp about how to build an event system. I don't think that this is my problem. Maybe i do not see something in that case i would be thankful if you could provide me with some more pointers. Sometimes you can miss the obvious. :)

    I got it working now but i still think that there should be a way to jobify this ComponentSystem.

    Code (csharp):
    1.  
    2. [UpdateBefore(typeof(DamageDoneBarrier))]
    3.     public class DealPhysicalDamageMain : ComponentSystem
    4.     {
    5.         private ComponentGroup _group;
    6.  
    7.         protected override void OnCreateManager()
    8.         {
    9.             base.OnCreateManager();
    10.             _group = GetComponentGroup(
    11.                 new ECSQueryBuilder().RequireReadOnly<PhysicalDamage>()
    12.                                       .RequireReadOnly<Target>()
    13.                                       .Build()
    14.             );
    15.         }
    16.  
    17.         protected override void OnUpdate()
    18.         {
    19.             var physicalDamageType = GetArchetypeChunkComponentType<PhysicalDamage>(true);
    20.             var targetType = GetArchetypeChunkComponentType<Target>(true);
    21.  
    22.             var map = new NativeMultiHashMap<Entity, int>(_group.CalculateLength(), Allocator.Temp);
    23.             var hashSet = new HashSet<Entity>();
    24.  
    25.             var chunks = _group.CreateArchetypeChunkArray(Allocator.TempJob);
    26.             for(var i = 0; i < chunks.Length; ++i)
    27.             {
    28.                 var chunk = chunks[i];
    29.                 var physicalDamages = chunk.GetNativeArray(physicalDamageType);
    30.                 var targets = chunk.GetNativeArray(targetType);
    31.                 for(var j = 0; j < chunk.Count; ++j)
    32.                 {
    33.                     var damage = physicalDamages[j].Value;
    34.                     var target = targets[j].Entity;
    35.  
    36.                     map.Add(target, damage);
    37.                     hashSet.Add(target);
    38.                 }
    39.             }
    40.             chunks.Dispose();
    41.  
    42.             foreach(var entity in hashSet)
    43.             {
    44.                 map.TryGetFirstValue(entity, out var damage, out var iterator);
    45.                 while(map.TryGetNextValue(out var addDamage, ref iterator))
    46.                 {
    47.                     damage += addDamage;
    48.                 }
    49.  
    50.                 EntityManager.AddComponentData(entity, new PhysicalDamageReceived { Value = damage });
    51.             }
    52.            
    53.             map.Dispose();
    54.         }
    55.     }
    56.