- Updated PhysicsPerceptionSystem to support seven detection modes: RangeCircle, BatchLOS, FanCast, BoxCast, Sight, RayCast, and TriggerZone. - Improved documentation for each detection mode, including performance optimization strategies. - Introduced PerceptionTriggerProxy for event-driven detection in TriggerZone slots. - Added SightBatchSystem to manage Sight slots efficiently, reducing CPU spikes during high enemy counts. - Updated SensorSlotNames to reflect new detection modes and their purposes. - Enhanced internal logic for detecting targets and managing detection events.
108 lines
5.0 KiB
C#
108 lines
5.0 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace BaseGames.Enemies.Perception
|
||
{
|
||
/// <summary>
|
||
/// 场景级 Sight 槽位批量调度器(Phase 3 性能优化)。
|
||
///
|
||
/// <b>设计意图:</b>
|
||
/// Sight 槽位内置多点 LOS 射线检测,当场景中存在大量敌人时(10+ 个),
|
||
/// 每帧同步刷新所有 Sight 槽位会产生明显的 CPU 峰值。
|
||
/// 本组件将全局 Sight 更新量限制在 <see cref="maxSystemsPerFrame"/> 个/帧,
|
||
/// 通过轮询方式公平分配每帧的 Sight 预算,把瞬时峰值摊平到多帧。
|
||
///
|
||
/// <b>使用方式:</b>
|
||
/// 1. 在场景中添加一个空 GameObject,挂载本组件(建议放在 Managers 节点下)。
|
||
/// 2. 本组件自动在 <c>DefaultExecutionOrder(-50)</c> 执行,比默认 PhysicsPerceptionSystem 早。
|
||
/// 3. 当本组件存在时,PhysicsPerceptionSystem.FixedUpdate() 会跳过所有 Sight 槽位的更新,
|
||
/// 由本组件统一调度(优雅降级:本组件不存在时 Sight 每帧正常更新)。
|
||
///
|
||
/// <b>性能参考(测试用):</b>
|
||
/// • maxSystemsPerFrame = 4,60fps,20 个敌人 → 平均每帧 4 × losRayCount 次射线,
|
||
/// 每个敌人 Sight 刷新周期约 5 帧(~83ms),适合慢速视线感应。
|
||
/// • 增大此值可减少延迟,减小此值可进一步降低每帧开销。
|
||
/// </summary>
|
||
[AddComponentMenu("BaseGames/Enemies/Sight Batch System")]
|
||
[DefaultExecutionOrder(-50)]
|
||
public sealed class SightBatchSystem : MonoBehaviour
|
||
{
|
||
// ── 单例 ──────────────────────────────────────────────────────────────
|
||
|
||
public static SightBatchSystem Instance { get; private set; }
|
||
|
||
// ── 配置 ──────────────────────────────────────────────────────────────
|
||
|
||
[Min(1)]
|
||
[Tooltip("每帧最多更新多少个 PhysicsPerceptionSystem 的 Sight 槽位。\n" +
|
||
"建议值:场景敌人数 / 5(使平均刷新延迟 ≈ 5 帧)。\n" +
|
||
"值越大 = 延迟越低但 CPU 峰值越高;值越小反之。")]
|
||
[SerializeField] private int maxSystemsPerFrame = 4;
|
||
|
||
// ── 内部状态 ──────────────────────────────────────────────────────────
|
||
|
||
private readonly List<PhysicsPerceptionSystem> _registrants =
|
||
new List<PhysicsPerceptionSystem>(32);
|
||
|
||
private int _offset;
|
||
|
||
// ── 单例生命周期 ──────────────────────────────────────────────────────
|
||
|
||
private void Awake()
|
||
{
|
||
if (Instance != null && Instance != this)
|
||
{
|
||
Debug.LogWarning("[SightBatchSystem] 场景中存在多个 SightBatchSystem,将销毁多余实例。", this);
|
||
Destroy(gameObject);
|
||
return;
|
||
}
|
||
Instance = this;
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
if (Instance == this) Instance = null;
|
||
}
|
||
|
||
// ── 注册 / 注销 ───────────────────────────────────────────────────────
|
||
|
||
/// <summary>PhysicsPerceptionSystem.Awake() 自动调用。</summary>
|
||
public void Register(PhysicsPerceptionSystem system)
|
||
{
|
||
if (system == null || _registrants.Contains(system)) return;
|
||
_registrants.Add(system);
|
||
}
|
||
|
||
/// <summary>PhysicsPerceptionSystem.OnDestroy() 自动调用。O(1) 交换删除。</summary>
|
||
public void Unregister(PhysicsPerceptionSystem system)
|
||
{
|
||
int idx = _registrants.IndexOf(system);
|
||
if (idx < 0) return;
|
||
int last = _registrants.Count - 1;
|
||
_registrants[idx] = _registrants[last];
|
||
_registrants.RemoveAt(last);
|
||
|
||
// 防止 _offset 越界
|
||
if (_offset >= _registrants.Count)
|
||
_offset = 0;
|
||
}
|
||
|
||
// ── 调度 ──────────────────────────────────────────────────────────────
|
||
|
||
private void FixedUpdate()
|
||
{
|
||
int total = _registrants.Count;
|
||
if (total == 0) return;
|
||
|
||
int budget = Mathf.Min(maxSystemsPerFrame, total);
|
||
for (int i = 0; i < budget; i++)
|
||
{
|
||
int idx = (_offset + i) % total;
|
||
_registrants[idx].ExecuteSightSlots();
|
||
}
|
||
|
||
_offset = (_offset + budget) % total;
|
||
}
|
||
}
|
||
}
|