Search Unity

DOTS Looping Best Practice Help

Discussion in 'Data Oriented Technology Stack' started by Plummers, May 1, 2020.

  1. Plummers

    Plummers

    Joined:
    Oct 29, 2015
    Posts:
    31
    Hi, I have my code working as posted below. However it seems really inefficient. Still a noob at DOTS so appreciate all advice, thanks.

    Goal:
    1. Each mage casts revive spell when cooldown reached.
    2. Revive checks mage distance to every dead body and revives those in range.

    Problem:
    1. Every update loop I am updating the list of dead bodies and their positions, ideally I would only update this list when the spell is due to be cast. Is that possible?
    2. I've noticed large Garbage Collection spikes, am I disposing of the NativeArrays correctly?

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Mathematics;
    5. using Unity.Transforms;
    6. using UnityEngine;
    7.  
    8.  
    9. public struct Mage : IComponentData
    10. {
    11.     public float Cooldown, Timer;
    12. }
    13.  
    14. public class MageAuthoring : MonoBehaviour, IConvertGameObjectToEntity
    15. {
    16.     [Tooltip("The time before they can cast <revive> again.")]
    17.     public float Cooldown, Timer;
    18.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    19.     {
    20.         dstManager.AddComponentData(entity,
    21.             new Mage
    22.             {
    23.                 Cooldown = Cooldown,
    24.                 Timer = Timer
    25.             });
    26.     }
    27. }
    28.  
    29. public class MageSystem : SystemBase
    30. {
    31.     EntityCommandBufferSystem Barrier;
    32.     protected override void OnCreate()
    33.     {
    34.         Barrier = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    35.     }
    36.  
    37.     protected unsafe override void OnUpdate()
    38.     {
    39.         float deltaTime = Time.DeltaTime;
    40.         var commandBuffer = Barrier.CreateCommandBuffer().ToConcurrent();
    41.  
    42.         NativeArray<Translation> deadPositions = GetEntityQuery(ComponentType.ReadOnly<LifeTime>(), typeof(Translation)).ToComponentDataArray<Translation>(Allocator.TempJob);
    43.         NativeArray<Entity> deadPeople = GetEntityQuery(ComponentType.ReadOnly<LifeTime>()).ToEntityArray(Allocator.TempJob);
    44.  
    45.         Entities.ForEach((Entity entity, int entityInQueryIndex, ref Mage mage, in Translation trans) =>
    46.         {
    47.             float distance = 0;
    48.             int i = 0;
    49.             if (mage.Timer < mage.Cooldown)
    50.             {
    51.                 mage.Timer += deltaTime;
    52.             }
    53.             else
    54.             {
    55.                 mage.Timer = 0;
    56.  
    57.                 while (i < deadPositions.Length)
    58.                 {
    59.                     distance = math.distance(trans.Value, deadPositions[i].Value);
    60.                     if (distance < 20)
    61.                     {
    62.                         commandBuffer.AddComponent<Reviving>(entityInQueryIndex, deadPeople[i]);
    63.                         commandBuffer.RemoveComponent<LifeTime>(entityInQueryIndex, deadPeople[i]);
    64.                     }
    65.                     i++;
    66.                 }
    67.             }
    68.         }).WithDeallocateOnJobCompletion(deadPositions).WithDeallocateOnJobCompletion(deadPeople).ScheduleParallel();
    69.     }
    70. }
     
  2. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    Just a small feedback for the moment: It's a good idea to cache entity queries (such as
    GetEntityQuery(ComponentType.ReadOnly<LifeTime>(), typeof(Translation))
    ) in instance variables in the OnCreate method. Otherwise it'll perform many entity query cache lookups.
     
  3. Plummers

    Plummers

    Joined:
    Oct 29, 2015
    Posts:
    31
    Hi Florian, thanks for the feedback. The problem is that the entity query results are constantly changing. So it needs to be up to date for when the mage casts 'revive'.
     
  4. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    The query is a query, not the results. Look at it as a database query – the results change based on the data it queries. But the query itself can be remembered (a standard pattern). I hope that helps :)
     
    Last edited: May 1, 2020
    Fribur and Plummers like this.
unityunity