145 lines
4.8 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|