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

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
}
}