174 lines
6.7 KiB
C#
174 lines
6.7 KiB
C#
using SepCore.Debugger;
|
|
using SepCore.Entity;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
|
|
namespace SepCore.Simulation
|
|
{
|
|
public sealed partial class SimulationWorld
|
|
{
|
|
#region Collision Broad Phase
|
|
|
|
private void PrepareCollisionCandidatesForFrame()
|
|
{
|
|
_collisionCandidateQueryScheduled = false;
|
|
|
|
if (!_collisionQueryInputs.IsCreated || !_collisionCandidates.IsCreated ||
|
|
!_enemyCollisionBuckets.IsCreated)
|
|
{
|
|
ResetCollisionRuntimeStats();
|
|
ClearAreaCollisionTransientBuffers();
|
|
return;
|
|
}
|
|
|
|
int projectileCount = _projectiles.Count;
|
|
int areaQueryCount = _areaCollisionRequests.Count;
|
|
if (projectileCount == 0 && areaQueryCount == 0)
|
|
{
|
|
ResetCollisionRuntimeStats();
|
|
return;
|
|
}
|
|
|
|
float queryRadius = Mathf.Max(0.01f, _projectileCollisionQueryRadius);
|
|
int maxCandidatesPerQuery = Mathf.Max(1, _projectileMaxCandidatesPerQuery);
|
|
float maxQueryRadius = queryRadius;
|
|
int queryId = 0;
|
|
int projectileQueryCount = 0;
|
|
int builtAreaQueryCount = 0;
|
|
using (CustomProfilerMarker.Collision_BuildQueries.Auto())
|
|
{
|
|
for (int i = 0; i < projectileCount; i++)
|
|
{
|
|
if (!_projectiles.Life[i].Active)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ProjectileTransformSim projectileTransform = _projectiles.Transform[i];
|
|
ProjectileIdentitySim projectileIdentity = _projectiles.Identity[i];
|
|
AddProjectileCollisionQuery(queryId, in projectileTransform, in projectileIdentity, queryRadius,
|
|
maxCandidatesPerQuery);
|
|
queryId++;
|
|
projectileQueryCount++;
|
|
}
|
|
|
|
for (int i = 0; i < areaQueryCount; i++)
|
|
{
|
|
AreaCollisionRequestData request = _areaCollisionRequests[i];
|
|
AddAreaCollisionQuery(queryId, request.SourceEntityId, request.SourceOwnerEntityId,
|
|
request.SourceWasActiveAtQueryTime, in request.Center, request.Radius, request.MaxTargets,
|
|
request.ShapeType, in request.Direction, request.HalfAngleDeg, request.HalfWidth,
|
|
request.HalfLength);
|
|
queryId++;
|
|
builtAreaQueryCount++;
|
|
if (request.Radius > maxQueryRadius)
|
|
{
|
|
maxQueryRadius = request.Radius;
|
|
}
|
|
}
|
|
}
|
|
|
|
_lastProjectileCollisionQueryCount = projectileQueryCount;
|
|
_lastAreaCollisionQueryCount = builtAreaQueryCount;
|
|
_lastCollisionQueryCount = projectileQueryCount + builtAreaQueryCount;
|
|
_lastResolvedAreaHitCount = 0;
|
|
|
|
if (_collisionQueryInputs.Length == 0)
|
|
{
|
|
_lastCollisionCandidateCount = 0;
|
|
_lastProjectileCollisionCandidateCount = 0;
|
|
_lastAreaCollisionCandidateCount = 0;
|
|
_lastCollisionCellSize = 0f;
|
|
_lastCollisionHasEnemyTargets = _enemies.Count > 0;
|
|
return;
|
|
}
|
|
|
|
float autoCellSize = maxQueryRadius * 2f;
|
|
float configuredCellSize = _projectileCollisionCellSize > 0f ? _projectileCollisionCellSize : autoCellSize;
|
|
float cellSize = Mathf.Max(0.1f, configuredCellSize);
|
|
bool hasEnemyTargets = _enemies.Count > 0;
|
|
_lastCollisionCellSize = cellSize;
|
|
_lastCollisionHasEnemyTargets = hasEnemyTargets;
|
|
|
|
using (CustomProfilerMarker.Collision_BuildBuckets.Auto())
|
|
{
|
|
if (hasEnemyTargets)
|
|
{
|
|
CollisionQuerySystem.BuildEnemyCollisionBuckets(_enemies, _enemyCollisionBuckets, cellSize);
|
|
}
|
|
}
|
|
|
|
using (CustomProfilerMarker.Collision_QueryCandidates.Auto())
|
|
{
|
|
bool hasPlayerTarget = TryGetPlayerCollisionTarget(out int playerTargetEntityId,
|
|
out float3 playerPosition);
|
|
_collisionCandidateQueryScheduled = CollisionQuerySystem.ScheduleCandidateQuery(
|
|
_collisionQueryInputs, _collisionCandidates, _enemyCollisionBuckets, _enemies, hasEnemyTargets,
|
|
hasPlayerTarget, playerTargetEntityId, playerPosition, cellSize,
|
|
out _collisionCandidateQueryHandle);
|
|
}
|
|
}
|
|
|
|
private void CompleteCollisionCandidatesForFrame()
|
|
{
|
|
if (_collisionCandidateQueryScheduled)
|
|
{
|
|
_collisionCandidateQueryHandle.Complete();
|
|
_collisionCandidateQueryScheduled = false;
|
|
}
|
|
|
|
CountCollisionCandidatesBySourceType(out int projectileCandidateCount, out int areaCandidateCount);
|
|
_lastProjectileCollisionCandidateCount = projectileCandidateCount;
|
|
_lastAreaCollisionCandidateCount = areaCandidateCount;
|
|
_lastCollisionCandidateCount = projectileCandidateCount + areaCandidateCount;
|
|
}
|
|
|
|
private void CountCollisionCandidatesBySourceType(out int projectileCandidateCount, out int areaCandidateCount)
|
|
{
|
|
projectileCandidateCount = 0;
|
|
areaCandidateCount = 0;
|
|
|
|
if (!_collisionCandidates.IsCreated)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < _collisionCandidates.Length; i++)
|
|
{
|
|
CollisionCandidateData candidate = _collisionCandidates[i];
|
|
if (candidate.SourceType == SimulationCollision.SourceTypeProjectile)
|
|
{
|
|
projectileCandidateCount++;
|
|
}
|
|
else if (candidate.SourceType == SimulationCollision.SourceTypeArea)
|
|
{
|
|
areaCandidateCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool TryGetPlayerCollisionTarget(out int playerEntityId, out float3 playerPosition)
|
|
{
|
|
playerEntityId = PlayerEntityId;
|
|
playerPosition = default;
|
|
|
|
if (!TryGetAliveTargetableEntity(playerEntityId, out TargetableObject playerTarget))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Transform playerTransform = playerTarget.CachedTransform;
|
|
if (playerTransform == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Vector3 position = playerTransform.position;
|
|
playerPosition = new float3(position.x, position.y, position.z);
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|