feat(enemy): E001 追击改为冲刺+冷却(朝玩家方向冲,撞墙/边缘停,CD后再冲)

按新设计:进入追击→Skill_Start(张口)→起手后按玩家所在侧一次性确定方向→
速度直冲(非 nav,接触伤害开)→撞墙/到平台边缘(WouldBlockAhead)或受阻即停→
Skill_End(收招)→进入冷却(ABL_E001_Chase.cooldown=1s)。一次冲刺=一次能力执行,
AI 追击态在冷却结束时经 EnsureAbility 重触发下一次冲刺。

- ContactChaseAbility:无限跟随改为有限冲刺;方向 committed(会越过跳开的玩家,
  可被躲);加窗口净位移卡死兜底——撞上未在检测层的碰撞体(玩家/边界墙)原地不动
  时结束冲刺转收招+冷却,避免卡死。
- ABL_E001_Chase.cooldown 0→1(可在 SO 调)。

PlayMode 验证(净域重载后):Skill_Start→冲刺(实测冲 7 单位、伤害开)→受阻→
Skill_End→冷却→冷却结束重新起手冲刺,完整循环。速度直冲不依赖 nav,敌人实际
位移正常。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
This commit is contained in:
2026-07-10 16:46:37 +08:00
parent 36aa2006e4
commit 9eca69a6ba
2 changed files with 31 additions and 12 deletions
@@ -14,7 +14,7 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
abilityId: e001_chase abilityId: e001_chase
attackSequence: [] attackSequence: []
cooldown: 0 cooldown: 1
telegraphVfxKey: telegraphVfxKey:
telegraphDuration: 0 telegraphDuration: 0
interruptOnHurt: 1 interruptOnHurt: 1
@@ -5,10 +5,11 @@ using UnityEngine;
namespace BaseGames.Enemies.Abilities namespace BaseGames.Enemies.Abilities
{ {
/// <summary> /// <summary>
/// 追击 + 体接触伤害能力:起手(Skill_Start 张口) → 循环追击(Skill_Loop 快速爬行 + 接触伤害) /// 冲刺追击 + 体接触伤害能力:起手(Skill_Start 张口) → 朝玩家方向直冲(Skill_Loop 快速爬行 +
/// → 收招(Skill_End)。追击动画由本能力全权驱动(Approach 模式不驱动步态,避免抢动画)。 /// 接触伤害),**直到撞墙/到平台边缘或玩家消失即停** → 收招(Skill_End)。一次冲刺为一次能力执行,
/// 何时停止由 AI 决策层负责:AI 在"脱离感知"时中断本能力(ExternalRequest),本能力播 Skill_End 收招 /// 结束后进入冷却(EnemyAbilitySO.cooldown)AI 追击态在冷却结束时经 EnsureAbility 重触发下一次冲刺
/// 依据 Docs/Game/Design/小怪设计-程序开发文档-01.mdE001 状态机 Skill_Start/Loop/End)。 /// 冲刺方向在起手后按玩家所在侧一次性确定(committed 冲锋,会越过跳开的玩家,可被躲)。
/// 追击动画由本能力全权驱动(Approach 步态不抢动画)。
/// </summary> /// </summary>
public class ContactChaseAbility : EnemyAbilityBase public class ContactChaseAbility : EnemyAbilityBase
{ {
@@ -33,20 +34,38 @@ namespace BaseGames.Enemies.Abilities
yield return EnemyAbilityWaits.Get(_startClip.Clip.length); yield return EnemyAbilityWaits.Get(_startClip.Clip.length);
} }
// 循环追击:切追击速度、开接触伤害、朝玩家移动,播 Skill_Loop(Approach 模式不抢步态)。 // 冲刺方向:起手后按玩家所在侧一次性确定(committed 冲锋)
if (_enemy.Nav != null && _enemy.Stats != null) float dir = (_enemy.PlayerTransform != null &&
_enemy.Nav.SetSpeed(_enemy.Stats.RunSpeed); _enemy.PlayerTransform.position.x < _enemy.transform.position.x) ? -1f : 1f;
float speed = _enemy.Stats != null ? _enemy.Stats.RunSpeed : 0f;
var mv = _enemy.Movement;
// 冲刺:朝该方向直冲、接触伤害开、播 Skill_Loop,直到撞墙/到边缘或玩家消失即停。
if (_loopClip.Clip != null) if (_loopClip.Clip != null)
_animancer.Play(_loopClip); _animancer.Play(_loopClip);
if (_contactDamage != null) if (_contactDamage != null)
_contactDamage.enabled = true; _contactDamage.enabled = true;
// 追击直到玩家消失或被 AI 中断(退出追击的决策归 AI)。小怪走 nav 寻路。 float winX = _enemy.transform.position.x;
_enemy.Locomotion?.Approach(_enemy.PlayerTransform); float winT = 0f;
while (_enemy.PlayerTransform != null) while (_enemy.PlayerTransform != null && !(mv != null && mv.WouldBlockAhead(dir)))
{
_enemy.MoveInDirectionWithSpeed(dir, speed); // 速度直冲(非 nav)MoveWithSpeed 悬崖夹紧兜底
yield return null; yield return null;
// 玩家对象消失(正常收尾):收招 Skill_End // 兜底:撞上未在检测层的碰撞体(玩家/边界墙)导致原地不动 → 结束本次冲刺(转收招+冷却)
// 用窗口净位移判定,避免"贴住微抖"每帧重置。
winT += Time.deltaTime;
if (winT >= 0.15f)
{
if (Mathf.Abs(_enemy.transform.position.x - winX) < 0.05f) break;
winX = _enemy.transform.position.x;
winT = 0f;
}
}
_enemy.StopMovement();
// 收招 Skill_End;随后基类按 EnemyAbilitySO.cooldown 施加冷却。
DisableContact(); DisableContact();
yield return PlaySkillEnd(); yield return PlaySkillEnd();
Cleanup(); Cleanup();