Skip to content

Instantly share code, notes, and snippets.

@admal
Last active October 1, 2020 01:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save admal/bf91c434ee31934143109b201fe7ec8b to your computer and use it in GitHub Desktop.
Save admal/bf91c434ee31934143109b201fe7ec8b to your computer and use it in GitHub Desktop.
Unity dots: migration to new DOTS
public class FindTargetSystem : SystemBase
{
private EndSimulationEntityCommandBufferSystem ecbSystem;
protected override void OnCreate()
{
ecbSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
base.OnCreate();
}
public struct EntityWithPosition
{
public Entity entity;
public float3 position;
}
protected override void OnUpdate()
{
//It is needed to use instead of PostUpdateCommands
var ecb = ecbSystem.CreateCommandBuffer().ToConcurrent();
//EnemyUnit == Target
var enemiesQuery = GetEntityQuery(typeof(EnemyUnit), ComponentType.ReadOnly<Translation>());
var enemiesEntityArray = enemiesQuery.ToEntityArray(Allocator.TempJob);
var enemiesTranslationArray = enemiesQuery.ToComponentDataArray<Translation>(Allocator.TempJob);
var enemiesArray = new NativeArray<EntityWithPosition>(enemiesEntityArray.Length, Allocator.TempJob);
for (int i = 0; i < enemiesEntityArray.Length; i++)
{
enemiesArray[i] = new EntityWithPosition()
{
entity = enemiesEntityArray[i],
position = enemiesTranslationArray[i].Value
};
}
//Put quadrant map into class variable, to use burst and jobs in dots you can't pass static fields.
//Thanks to that multihashmap is a struct so only value is copied to local variable.
//That variable is later used inside of the ForEach method.
var quadrantMultiHashMap = QuadrantSystem.quadrantMultiHashMap;
//That code uses jobs and burst
Entities
//WithReadOnly - you can read in parallel
.WithReadOnly(quadrantMultiHashMap)
.WithNone<HasTarget>()
.WithAll<PlayerUnit>()
.ForEach((Entity entity, int entityInQueryIndex, ref Translation translation, ref QuadrantEntity quadrantEntity) =>
{
var closestEnemy = Entity.Null;
var closestEnemyPosition = float3.zero;
var unitPosition = translation.Value;
var hashMapKey = QuadrantSystem.GetPositionHashMapKey(translation.Value);
//This little hack allows you to use 'static' stuff inside jobs (you can't use class' methods nor truly static methods here)
var helper = new TargetHelper();
helper.FindTarget(quadrantMultiHashMap, hashMapKey, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
helper.FindTarget(quadrantMultiHashMap, hashMapKey + 1, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
helper.FindTarget(quadrantMultiHashMap, hashMapKey - 1, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
helper.FindTarget(quadrantMultiHashMap, hashMapKey + QuadrantSystem.QuadrantZMultiplier, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
helper.FindTarget(quadrantMultiHashMap, hashMapKey - QuadrantSystem.QuadrantZMultiplier, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
helper.FindTarget(quadrantMultiHashMap, hashMapKey + 1 - QuadrantSystem.QuadrantZMultiplier, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
helper.FindTarget(quadrantMultiHashMap, hashMapKey - 1 - QuadrantSystem.QuadrantZMultiplier, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
helper.FindTarget(quadrantMultiHashMap, hashMapKey + 1 + QuadrantSystem.QuadrantZMultiplier, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
helper.FindTarget(quadrantMultiHashMap, hashMapKey - 1 + QuadrantSystem.QuadrantZMultiplier, unitPosition, quadrantEntity, ref closestEnemy, ref closestEnemyPosition);
if (closestEnemy != Entity.Null)
{
ecb.AddComponent<HasTarget>(entityInQueryIndex, entity, new HasTarget() { targetEntity = closestEnemy });
}
})
.ScheduleParallel();
enemiesEntityArray.Dispose(Dependency);
enemiesTranslationArray.Dispose(Dependency);
enemiesArray.Dispose(Dependency);
// quadrantMultiHashMap.Dispose(Dependency); //I don't know why this part does not work, but in my opinion it should be disposed
ecbSystem.AddJobHandleForProducer(Dependency);
}
private struct TargetHelper
{
public void FindTarget(
NativeMultiHashMap<int, QuadrantData> quadrantMap,
int hashMapKey,
float3 unitPosition,
QuadrantEntity quadrantEntity,
ref Entity closestEnemy,
ref float3 closestEnemyPosition
)
{
NativeMultiHashMapIterator<int> nativeMultiHashMapIterator;
if (quadrantMap.TryGetFirstValue(hashMapKey, out var quadrantData, out nativeMultiHashMapIterator))
{
do
{
if (quadrantData.quadrantEntity.type == quadrantEntity.type)
{
continue;
}
if (closestEnemy == Entity.Null)
{
//no target
closestEnemy = quadrantData.entity;
closestEnemyPosition = quadrantData.position;
}
else
{
if (math.distance(unitPosition, quadrantData.position) < math.distance(unitPosition, closestEnemyPosition))
{
closestEnemy = quadrantData.entity;
closestEnemyPosition = quadrantData.position;
}
}
} while (quadrantMap.TryGetNextValue(out quadrantData, ref nativeMultiHashMapIterator));
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment