feat(enemy): E001 追击动画 Skill_Start/Loop/End 完整化,符合设计文档

依据 Docs/Game/Design/小怪设计-程序开发文档-01.md:感知→Skill_Start(张口,单次)
→Skill_Loop(快速爬行追击,循环)→丢失目标→Skill_End(收招,单次)→Move_Patrol,
E001 无警觉态。

原问题:ContactChaseAbility 的 loop/end clip 都空、无 start clip,追击全程无
动画;Approach 步态还错播 Move;有多余警觉态(Alert clip 也空)。

- ContactChaseAbility:加 _startClip;协程 Skill_Start(锁动画+等时长,不伤人)→
  开伤害+Approach+Skill_Loop(循环)→退出播 Skill_End。丢失目标(ExternalRequest
  中断)播 Skill_End;受击/死亡硬打断不播。
- EnemyBase:加动画锁 LockAnim/IsAnimLocked——一次性招式动画期间步态不覆盖;
  PlayLocomotionClip 的 Approach 改为不驱动步态(追击动画归能力)。
- EnemyLocomotion:锁定期不算"已应用",解锁后重同步步态(避免卡在 Skill_End)。
- ENM_E001_Stats:HasAlertState=false(设计无警觉态)。
- prefab + 脚手架:ContactChaseAbility 接线 Skill_Start/Loop/End;新增
  AssignClipTransition 助手(按名+路径定位同名 clip)。

PlayMode 验证:Skill_Start(locked/不伤人)→Skill_Loop(伤害开)→Skill_End
(locked)→步态恢复 Move,全链符合设计。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
This commit is contained in:
2026-07-10 16:27:02 +08:00
parent f1ca62f881
commit 36aa2006e4
6 changed files with 190 additions and 109 deletions
+14 -3
View File
@@ -416,16 +416,27 @@ namespace BaseGames.Enemies
ScheduleStateRecovery(EnemyStateType.Stagger, staggerDuration);
}
/// <summary>按当前移动模式播放步态动画(由 EnemyLocomotion 在模式变化时调用)。</summary>
// 动画锁:一次性招式动画(如追击 Skill_Start/Skill_End)播放期间,禁止步态动画覆盖它。
private float _animLockUntil;
/// <summary>是否处于一次性招式动画锁定中(步态不应覆盖)。</summary>
public bool IsAnimLocked => Time.time < _animLockUntil;
/// <summary>锁定动画 <paramref name="duration"/> 秒,期间步态动画不覆盖(供能力播放起手/收招等一次性动作)。</summary>
public void LockAnim(float duration) => _animLockUntil = Time.time + Mathf.Max(0f, duration);
/// <summary>
/// 按当前移动模式播放步态动画(由 EnemyLocomotion 在模式变化时调用)。
/// Approach(追击)不在此驱动——追击动画由能力(Skill_Start/Loop/End)全权驱动,避免抢动画。
/// 招式动画锁定期间(<see cref="IsAnimLocked"/>)不覆盖。
/// </summary>
public void PlayLocomotionClip(LocomotionMode mode)
{
if (_animancer == null || _animConfig == null) return;
if (_animancer == null || _animConfig == null || IsAnimLocked) return;
var clip = mode switch
{
LocomotionMode.Idle => _animConfig.Idle,
LocomotionMode.Patrol => _animConfig.Walk,
LocomotionMode.Face => _animConfig.Alert,
LocomotionMode.Approach => _animConfig.Run,
LocomotionMode.Approach => null, // 追击动画归能力驱动
_ => null,
};
if (clip != null) _animancer.Play(clip);