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