Files
vampire-like/Assets/GameMain/Scripts/Runtime/CustomComponent/Simulation/SimulationWorld.TargetSelectionSpatialIndex.cs
T

145 lines
4.8 KiB
C#

using SepCore.Debugger;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;
namespace SepCore.Simulation
{
public sealed partial class SimulationWorld
{
public bool TryGetNearestEnemyEntityId(Vector3 origin, float maxSqrRange, out int enemyEntityId)
{
enemyEntityId = 0;
if (maxSqrRange <= 0f || _enemies.Count == 0)
{
return false;
}
BuildEnemyTargetSpatialIndexIfNeeded();
float cellSize = GetTargetSelectionCellSize();
int centerCellX = SimulationCell.ToCell(origin.x, cellSize);
int centerCellZ = SimulationCell.ToCell(origin.z, cellSize);
float range = Mathf.Sqrt(maxSqrRange);
int queryRange = Mathf.Max(1, Mathf.CeilToInt(range / cellSize));
float minSqrDistance = maxSqrRange;
bool found = false;
using (CustomProfilerMarker.TargetSelection_QueryNeighbors.Auto())
{
for (int dx = -queryRange; dx <= queryRange; dx++)
{
for (int dz = -queryRange; dz <= queryRange; dz++)
{
long key = SimulationCell.Key(centerCellX + dx, centerCellZ + dz);
if (!_enemyTargetBuckets.TryGetFirstValue(key, out int enemyIndex,
out NativeParallelMultiHashMapIterator<long> iterator))
{
continue;
}
do
{
if (enemyIndex < 0 || enemyIndex >= _enemies.Count)
{
continue;
}
float3 enemyPosition = _enemies.Transform[enemyIndex].Position;
float deltaX = enemyPosition.x - origin.x;
float deltaZ = enemyPosition.z - origin.z;
float sqrDistance = deltaX * deltaX + deltaZ * deltaZ;
if (sqrDistance >= minSqrDistance)
{
continue;
}
minSqrDistance = sqrDistance;
enemyEntityId = _enemies.Identity[enemyIndex].EntityId;
found = true;
} while (_enemyTargetBuckets.TryGetNextValue(out enemyIndex, ref iterator));
}
}
}
return found;
}
private void InitializeEnemyTargetSpatialIndex()
{
if (_enemyTargetBuckets.IsCreated)
{
return;
}
_enemyTargetBuckets = new NativeParallelMultiHashMap<long, int>(256, Allocator.Persistent);
_enemyTargetBucketsDirty = true;
}
private void DisposeEnemyTargetSpatialIndex()
{
if (_enemyTargetBuckets.IsCreated)
{
_enemyTargetBuckets.Dispose();
}
_enemyTargetBuckets = default;
_enemyTargetBucketsDirty = true;
}
private void ClearEnemyTargetSpatialIndex()
{
if (_enemyTargetBuckets.IsCreated)
{
_enemyTargetBuckets.Clear();
}
_enemyTargetBucketsDirty = true;
}
private void MarkEnemyTargetSpatialIndexDirty()
{
_enemyTargetBucketsDirty = true;
}
private void BuildEnemyTargetSpatialIndexIfNeeded()
{
InitializeEnemyTargetSpatialIndex();
if (!_enemyTargetBucketsDirty)
{
return;
}
using (CustomProfilerMarker.TargetSelection_BuildBuckets.Auto())
{
int enemyCount = _enemies.Count;
int desiredCapacity = Mathf.Max(256, enemyCount * 2 + 1);
if (_enemyTargetBuckets.Capacity < desiredCapacity)
{
_enemyTargetBuckets.Capacity = desiredCapacity;
}
_enemyTargetBuckets.Clear();
float cellSize = GetTargetSelectionCellSize();
for (int i = 0; i < enemyCount; i++)
{
float3 enemyPosition = _enemies.Transform[i].Position;
int cellX = SimulationCell.ToCell(enemyPosition.x, cellSize);
int cellZ = SimulationCell.ToCell(enemyPosition.z, cellSize);
_enemyTargetBuckets.Add(SimulationCell.Key(cellX, cellZ), i);
}
}
_enemyTargetBucketsDirty = false;
}
private float GetTargetSelectionCellSize()
{
return Mathf.Max(0.1f, _targetSelectionCellSize);
}
}
}