133 lines
5.7 KiB
C#
133 lines
5.7 KiB
C#
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using Unity.Mathematics;
|
|
|
|
namespace Simulation
|
|
{
|
|
public sealed partial class SimulationWorld
|
|
{
|
|
[BurstCompile]
|
|
private struct QueryCollisionCandidatesBurstJob : IJobParallelFor
|
|
{
|
|
[ReadOnly] public NativeArray<CollisionQueryData> Queries;
|
|
[ReadOnly] public NativeParallelMultiHashMap<long, int> EnemyBuckets;
|
|
[ReadOnly] public NativeArray<EnemyJobOutputData> EnemyOutputs;
|
|
public NativeList<CollisionCandidateData>.ParallelWriter Candidates;
|
|
public bool HasEnemyTargets;
|
|
public bool HasPlayerTarget;
|
|
public int PlayerTargetEntityId;
|
|
public float3 PlayerPosition;
|
|
public float CellSize;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
CollisionQueryData query = Queries[index];
|
|
int centerCellX = (int)math.floor(query.Position.x / CellSize);
|
|
int centerCellZ = (int)math.floor(query.Position.z / CellSize);
|
|
int queryRange = math.max(1, (int)math.ceil(query.Radius / CellSize));
|
|
int selectedCount = 0;
|
|
bool reachedLimit = false;
|
|
|
|
if (HasPlayerTarget && query.SourceEntityId != PlayerTargetEntityId &&
|
|
query.SourceOwnerEntityId != PlayerTargetEntityId)
|
|
{
|
|
float3 playerPosition = PlayerPosition;
|
|
if (query.SourceType == CollisionSourceTypeArea)
|
|
{
|
|
playerPosition.y = query.Position.y;
|
|
}
|
|
float3 playerDelta = playerPosition - query.Position;
|
|
float playerSqrDistance = math.lengthsq(playerDelta);
|
|
float playerRadiusSqr = query.Radius * query.Radius;
|
|
if (playerSqrDistance <= playerRadiusSqr)
|
|
{
|
|
Candidates.AddNoResize(new CollisionCandidateData
|
|
{
|
|
QueryId = query.QueryId,
|
|
SourceType = query.SourceType,
|
|
SourceEntityId = query.SourceEntityId,
|
|
SourceOwnerEntityId = query.SourceOwnerEntityId,
|
|
TargetEntityId = PlayerTargetEntityId,
|
|
SqrDistance = playerSqrDistance
|
|
});
|
|
|
|
selectedCount++;
|
|
if (selectedCount >= query.MaxTargets)
|
|
{
|
|
reachedLimit = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!HasEnemyTargets || reachedLimit)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int dx = -queryRange; dx <= queryRange && !reachedLimit; dx++)
|
|
{
|
|
for (int dz = -queryRange; dz <= queryRange && !reachedLimit; dz++)
|
|
{
|
|
long key = SeparationCellKey(centerCellX + dx, centerCellZ + dz);
|
|
if (!EnemyBuckets.TryGetFirstValue(key, out int enemyIndex,
|
|
out NativeParallelMultiHashMapIterator<long> iterator))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
do
|
|
{
|
|
if (enemyIndex < 0 || enemyIndex >= EnemyOutputs.Length)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
EnemyJobOutputData enemy = EnemyOutputs[enemyIndex];
|
|
if (enemy.EntityId == query.SourceOwnerEntityId)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
float deltaY = query.SourceType == CollisionSourceTypeArea
|
|
? 0f
|
|
: enemy.Position.y - query.Position.y;
|
|
float3 delta = new float3(
|
|
enemy.Position.x - query.Position.x,
|
|
deltaY,
|
|
enemy.Position.z - query.Position.z);
|
|
float sqrDistance = math.lengthsq(delta);
|
|
float targetRadius = query.SourceType == CollisionSourceTypeArea
|
|
? math.max(0f, enemy.EnemyBodyRadius)
|
|
: 0f;
|
|
float effectiveRadius = query.Radius + targetRadius;
|
|
if (sqrDistance > effectiveRadius * effectiveRadius)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Candidates.AddNoResize(new CollisionCandidateData
|
|
{
|
|
QueryId = query.QueryId,
|
|
SourceType = query.SourceType,
|
|
SourceEntityId = query.SourceEntityId,
|
|
SourceOwnerEntityId = query.SourceOwnerEntityId,
|
|
TargetEntityId = enemy.EntityId,
|
|
SqrDistance = sqrDistance
|
|
});
|
|
|
|
selectedCount++;
|
|
|
|
if (selectedCount >= query.MaxTargets)
|
|
{
|
|
reachedLimit = true;
|
|
break;
|
|
}
|
|
} while (EnemyBuckets.TryGetNextValue(out enemyIndex, ref iterator));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|