fix(combat): HitBox 懒初始化,修复 Activate 早于 Awake 致接触判定碰撞体被禁用

BodyContactDamage.OnEnable 在 HitBox.Awake 之前调用 Activate 时 _directColliders 尚未收集,Activate 对空列表启用碰撞体、随后 Awake 又禁用碰撞体,导致接触伤害判定盒永久收不到 Trigger 事件、玩家不受碰撞伤害。原 BodyContactDamage 靠 Update 周期 re-Activate 掩盖了该时序问题,移除该循环后暴露。

将碰撞体/代理/服务缓存收集抽到 EnsureInitialized 懒初始化,Awake 与 Activate 都先调用,与脚本执行顺序无关。已实机验证:进入 Play 后碰撞体自动启用,玩家正常受到碰撞伤害。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 16:56:42 +08:00
parent d441518dfe
commit 8a0992c0e7

View File

@@ -86,6 +86,8 @@ namespace BaseGames.Combat
/// </summary> /// </summary>
public void Activate(DamageSourceSO source = null, Transform attacker = null) public void Activate(DamageSourceSO source = null, Transform attacker = null)
{ {
// 保证碰撞体已收集(防止 Activate 早于 Awake 调用时对空列表启用碰撞体)
EnsureInitialized();
_currentActivationId = _nextActivationId++; _currentActivationId = _nextActivationId++;
_currentSource = source ?? _defaultSource; _currentSource = source ?? _defaultSource;
_attackerTransform = attacker ?? transform; _attackerTransform = attacker ?? transform;
@@ -115,8 +117,21 @@ namespace BaseGames.Combat
if (source != null) _currentSource = source; if (source != null) _currentSource = source;
} }
private void Awake() // 懒初始化标记:保证碰撞体收集只做一次,且不被 Awake / Activate 的调用顺序影响
private bool _initialized;
private void Awake() => EnsureInitialized();
/// <summary>
/// 懒初始化:收集直属碰撞体 / 子代理 / 服务缓存,并将碰撞体置为禁用(默认关闭)。
/// Awake 与 Activate 都会调用——保证即使某组件(如 BodyContactDamage因脚本执行顺序
/// 在本组件 Awake 之前就调用 Activate(),碰撞体列表也已就绪。否则 Activate 会对空列表
/// 启用碰撞体、随后 Awake 再把碰撞体禁用,导致判定盒永久收不到 Trigger 事件。
/// </summary>
private void EnsureInitialized()
{ {
if (_initialized) return;
_initialized = true;
// 收集本节点上所有直属 Collider2D并验证 isTrigger // 收集本节点上所有直属 Collider2D并验证 isTrigger
_directColliders = GetComponents<Collider2D>(); _directColliders = GetComponents<Collider2D>();
foreach (var col in _directColliders) foreach (var col in _directColliders)