refactor(enemy): 删除 AiPhase 影子层,动画统一由 locomotion/反应态/能力驱动

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-10 13:38:27 +08:00
co-authored by Claude Opus 4.8
parent 347d0e2f50
commit d718b99685
7 changed files with 19 additions and 132 deletions
+11 -69
View File
@@ -88,14 +88,6 @@ namespace BaseGames.Enemies
private EnemyStateType _currentState;
public EnemyStateType CurrentState => _currentState;
// ── AI 行为阶段(独立于物理/战斗状态)────────────────────────────────
private AiPhase _currentAiPhase = AiPhase.Idle;
/// <summary>当前 AI 行为阶段(BD 任务读取;ForceState 不会改变此值)。</summary>
public AiPhase CurrentAiPhase => _currentAiPhase;
/// <summary>AI 行为阶段变更时触发,可用于驱动外部系统(音效/视觉效果等)。</summary>
public event System.Action<AiPhase> OnAiPhaseChanged;
// ── 导航语义(归位 / 搜查)────────────────────────────────────────────
/// <summary>Awake/Start 时记录的初始世界坐标,供 BD_ReturnToHome 归位使用。</summary>
public Vector2 HomePosition { get; private set; }
@@ -116,7 +108,6 @@ namespace BaseGames.Enemies
#if UNITY_EDITOR
[Header("── 运行时调试(仅 Editor)──")]
[SerializeField] private EnemyStateType _dbg_CurrentState;
[SerializeField] private AiPhase _dbg_AiPhase;
[SerializeField] private bool _dbg_HasPlayer;
[SerializeField] private Vector2 _dbg_LastKnownPos;
#endif
@@ -243,6 +234,10 @@ namespace BaseGames.Enemies
public EnemyAiBrain Brain => _brain;
private EnemyAiBrain _brain;
/// <summary>是否处于交战(追击/攻击)中——供群体警戒判断"已交战不降级"。由 Chase 能力置位。</summary>
public bool IsEngaged { get; private set; }
public void SetEngaged(bool engaged) => IsEngaged = engaged;
// ── BD 行为树接口(虚方法)────────────────────────────────────────
public virtual void MoveTo(Vector2 target)
@@ -446,45 +441,13 @@ namespace BaseGames.Enemies
public void ReceiveAlert(Transform sharedPlayerTransform, Vector2 lastKnownPos)
{
if (!IsAlive) return;
if (_currentAiPhase == AiPhase.Chase || _currentAiPhase == AiPhase.Combat) return;
if (IsEngaged) return;
// 同步玩家引用(若本敌人尚未感知到玩家)
if (sharedPlayerTransform != null && _playerTransform == null)
_playerTransform = sharedPlayerTransform;
LastKnownPlayerPosition = lastKnownPos;
SetAiPhase(AiPhase.Alert);
}
[Header("AI 行为阶段")]
[Tooltip("SetAiPhase 变更时是否自动播放 AnimConfig 中对应的阶段动画(如 Alert/Investigate")]
[SerializeField] private bool _autoPlayPhaseAnimation = true;
/// <summary>
/// 设置 AI 行为阶段,并广播 <see cref="OnAiPhaseChanged"/> 事件。
/// 若 <see cref="_autoPlayPhaseAnimation"/> 为 true,自动播放 AnimConfig 对应动画。
/// 由 BD TaskBD_SetAiPhase / BD_ChasePlayer 等)调用;
/// 不触发受击/死亡等 EnemyStateType 流程。
/// </summary>
public void SetAiPhase(AiPhase phase)
{
if (_currentAiPhase == phase) return;
_currentAiPhase = phase;
OnAiPhaseChanged?.Invoke(phase);
if (_autoPlayPhaseAnimation && _animancer != null && _animConfig != null)
{
var clip = phase switch
{
AiPhase.Alert => _animConfig.Alert,
AiPhase.Investigate => _animConfig.Investigate ?? _animConfig.Walk,
AiPhase.Patrol => _animConfig.Walk,
AiPhase.ReturnHome => _animConfig.Walk,
AiPhase.Chase => _animConfig.Run,
AiPhase.Idle => _animConfig.Idle,
_ => null,
};
if (clip != null) _animancer.Play(clip);
}
PlayLocomotionClip(LocomotionMode.Face);
}
/// <summary>按当前移动模式播放步态动画(由 EnemyLocomotion 在模式变化时调用)。</summary>
@@ -620,7 +583,6 @@ namespace BaseGames.Enemies
#if UNITY_EDITOR
_dbg_CurrentState = _currentState;
_dbg_AiPhase = _currentAiPhase;
_dbg_HasPlayer = _playerTransform != null;
_dbg_LastKnownPos = LastKnownPlayerPosition;
#endif
@@ -749,7 +711,7 @@ namespace BaseGames.Enemies
// 重置状态(对象池复用:跳过 Dead 终态守卫,强制恢复到 Controlled)
ForceStateRespawn(EnemyStateType.Controlled);
_currentAiPhase = AiPhase.Idle;
IsEngaged = false;
// 重置对象池复用相关的运行时感知数据
// 注意:_playerTransform 不重置(场景中玩家仍存在),只重置追踪历史
@@ -809,21 +771,11 @@ namespace BaseGames.Enemies
// ── 运行时:AI 状态标签(常态可见,无需选中)────────────────
if (Application.isPlaying)
{
Color phaseColor = _currentAiPhase switch
{
AiPhase.Idle => Color.gray,
AiPhase.Patrol => Color.green,
AiPhase.Alert => Color.yellow,
AiPhase.Chase => new Color(1f, 0.5f, 0f),
AiPhase.Combat => Color.red,
AiPhase.Investigate => Color.cyan,
AiPhase.ReturnHome => Color.blue,
_ => Color.white,
};
Color phaseColor = Color.yellow;
UnityEditor.Handles.color = phaseColor;
UnityEditor.Handles.Label(
transform.position + Vector3.up * 1.2f,
$"[{_currentAiPhase}] {_currentState}");
$"[{(_brain != null ? _brain.CurrentStateName : "-")}] {_currentState}");
}
// ── 运行时:LOS 连线 ────────────────────────────────────────
@@ -860,20 +812,10 @@ namespace BaseGames.Enemies
// 感知范围圆形 Gizmo 由 PhysicsPerceptionSystemEditor [DrawGizmo] 统一绘制,
// 此处不重复绘制。
// 运行时:选中时绘制 AiPhase 彩色外圆(突出显示当前状态)
// 运行时:选中时绘制 AI 状态外圆(突出显示当前决策状态)
if (Application.isPlaying)
{
Color phaseColor = _currentAiPhase switch
{
AiPhase.Idle => Color.gray,
AiPhase.Patrol => Color.green,
AiPhase.Alert => Color.yellow,
AiPhase.Chase => new Color(1f, 0.5f, 0f),
AiPhase.Combat => Color.red,
AiPhase.Investigate => Color.cyan,
AiPhase.ReturnHome => Color.blue,
_ => Color.white,
};
Color phaseColor = Color.yellow;
Gizmos.color = phaseColor;
Gizmos.DrawWireSphere(transform.position, 0.5f);
}