简单重构拆分 SimulationWorld
This commit is contained in:
+215
@@ -0,0 +1,215 @@
|
||||
using SepCore.Debugger;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace SepCore.Simulation
|
||||
{
|
||||
internal static class CollisionQuerySystem
|
||||
{
|
||||
// 读写集:R EnemyTransform / EnemyMoveConfig / EnemyIdentity / CollisionQueryData(瞬时)
|
||||
// W CollisionCandidateData(瞬时) / 敌人碰撞分桶
|
||||
public static void BuildEnemyCollisionBuckets(EnemyStore enemies,
|
||||
NativeParallelMultiHashMap<long, int> buckets, float cellSize)
|
||||
{
|
||||
buckets.Clear();
|
||||
int enemyCount = enemies.Count;
|
||||
if (enemyCount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BuildCollisionBucketsJob job = new BuildCollisionBucketsJob
|
||||
{
|
||||
Transforms = enemies.Transform.Data.AsArray(),
|
||||
Buckets = buckets.AsParallelWriter(),
|
||||
CellSize = cellSize
|
||||
};
|
||||
|
||||
using (CustomProfilerMarker.TickEnemies_Complete.Auto())
|
||||
{
|
||||
job.Schedule(enemyCount, 64).Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ScheduleCandidateQuery(NativeList<CollisionQueryData> queries,
|
||||
NativeList<CollisionCandidateData> candidates, NativeParallelMultiHashMap<long, int> enemyBuckets,
|
||||
EnemyStore enemies, bool hasEnemyTargets, bool hasPlayerTarget, int playerTargetEntityId,
|
||||
float3 playerPosition, float cellSize, out JobHandle handle)
|
||||
{
|
||||
handle = default;
|
||||
if (!queries.IsCreated || !candidates.IsCreated)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
candidates.Clear();
|
||||
int queryCount = queries.Length;
|
||||
if (queryCount == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QueryCollisionCandidatesJob job = new QueryCollisionCandidatesJob
|
||||
{
|
||||
Queries = queries.AsArray(),
|
||||
EnemyBuckets = enemyBuckets,
|
||||
EnemyTransforms = enemies.Transform.Data.AsArray(),
|
||||
EnemyConfigs = enemies.MoveConfig.Data.AsArray(),
|
||||
EnemyIdentities = enemies.Identity.Data.AsArray(),
|
||||
Candidates = candidates.AsParallelWriter(),
|
||||
HasEnemyTargets = hasEnemyTargets,
|
||||
HasPlayerTarget = hasPlayerTarget,
|
||||
PlayerTargetEntityId = playerTargetEntityId,
|
||||
PlayerPosition = playerPosition,
|
||||
CellSize = cellSize
|
||||
};
|
||||
|
||||
handle = job.Schedule(queryCount, 64);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
internal struct BuildCollisionBucketsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<EnemyTransformSim> Transforms;
|
||||
public NativeParallelMultiHashMap<long, int>.ParallelWriter Buckets;
|
||||
public float CellSize;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
float3 position = Transforms[index].Position;
|
||||
int cellX = SimulationCell.ToCell(position.x, CellSize);
|
||||
int cellZ = SimulationCell.ToCell(position.z, CellSize);
|
||||
Buckets.Add(SimulationCell.Key(cellX, cellZ), index);
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
internal struct QueryCollisionCandidatesJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<CollisionQueryData> Queries;
|
||||
[ReadOnly] public NativeParallelMultiHashMap<long, int> EnemyBuckets;
|
||||
[ReadOnly] public NativeArray<EnemyTransformSim> EnemyTransforms;
|
||||
[ReadOnly] public NativeArray<EnemyMoveConfigSim> EnemyConfigs;
|
||||
[ReadOnly] public NativeArray<EnemyIdentitySim> EnemyIdentities;
|
||||
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 = SimulationCell.ToCell(query.Position.x, CellSize);
|
||||
int centerCellZ = SimulationCell.ToCell(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 == SimulationCollision.SourceTypeArea)
|
||||
{
|
||||
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 = SimulationCell.Key(centerCellX + dx, centerCellZ + dz);
|
||||
if (!EnemyBuckets.TryGetFirstValue(key, out int enemyIndex,
|
||||
out NativeParallelMultiHashMapIterator<long> iterator))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (enemyIndex < 0 || enemyIndex >= EnemyTransforms.Length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EnemyIdentitySim identity = EnemyIdentities[enemyIndex];
|
||||
if (identity.EntityId == query.SourceOwnerEntityId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EnemyTransformSim enemyTransform = EnemyTransforms[enemyIndex];
|
||||
float deltaY = query.SourceType == SimulationCollision.SourceTypeArea
|
||||
? 0f
|
||||
: enemyTransform.Position.y - query.Position.y;
|
||||
float3 delta = new float3(
|
||||
enemyTransform.Position.x - query.Position.x,
|
||||
deltaY,
|
||||
enemyTransform.Position.z - query.Position.z);
|
||||
float sqrDistance = math.lengthsq(delta);
|
||||
float targetRadius = query.SourceType == SimulationCollision.SourceTypeArea
|
||||
? math.max(0f, EnemyConfigs[enemyIndex].BodyRadius)
|
||||
: 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 = identity.EntityId,
|
||||
SqrDistance = sqrDistance
|
||||
});
|
||||
|
||||
selectedCount++;
|
||||
|
||||
if (selectedCount >= query.MaxTargets)
|
||||
{
|
||||
reachedLimit = true;
|
||||
break;
|
||||
}
|
||||
} while (EnemyBuckets.TryGetNextValue(out enemyIndex, ref iterator));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user