Files
zeling_v2/Assets/_Game/Scripts/Enemies/Abilities/ContactChaseAbility.cs
T
joywayerandClaude Opus 4.8 6c27993e09 feat(ai): 敌人感知↔状态模型——待机/警觉/追击/巡逻 + 可复用感知状态机
感知门面 EnemyBase.InChaseZone(追逐/aggro)/InVisionZone(视野/los,缺省回退aggro),纯查询;
转换逻辑归 AI 层: 新增可复用 PerceptionStateMachine(统一规则,HasAlert/视野缺省自动降级);
规则: 未发现进视野→警觉, 进追逐→追击(委托能力), 追击脱离视野→巡逻(永不回警觉,再进视野再警觉).
EnemyStatsSO.HasAlertState 勾选项; ContactChaseAbility 改纯执行器(退出由AI中断); E001 用可复用件.
PlayMode 验证四态转换全通过.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 15:10:39 +08:00

58 lines
1.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using Animancer;
using UnityEngine;
namespace BaseGames.Enemies.Abilities
{
/// <summary>
/// 循环追击 + 体接触伤害能力(纯执行器)。
/// 每帧 MoveTo 追向玩家、开接触伤害;**何时停止由 AI 决策层负责**——AI 在"脱离视野"时
/// 中断本能力(AI decides when to stop, ability implements the chase)。
/// 可复用于任何需要"追击+接触伤害循环"的敌人。
/// </summary>
public class ContactChaseAbility : EnemyAbilityBase
{
[Header("动画")]
[SerializeField] private ClipTransition _loopClip;
[SerializeField] private ClipTransition _endClip;
[Header("接触伤害")]
[SerializeField] private BodyContactDamage _contactDamage;
protected override IEnumerator ExecuteCoroutine()
{
Phase = AbilityRunState.Active;
if (_loopClip.Clip != null)
_animancer.Play(_loopClip);
if (_contactDamage != null)
_contactDamage.enabled = true;
// 追击直到玩家消失或被 AI 中断(退出追击的决策归 AI,见 EnemyBrainContext.InterruptAbilities
while (_enemy.PlayerTransform != null)
{
_enemy.MoveTo(_enemy.PlayerTransform.position);
yield return null;
}
CleanupChase();
if (_endClip.Clip != null)
{
_animancer.Play(_endClip);
yield return EnemyAbilityWaits.Get(_endClip.Clip.length);
}
}
protected override void OnInterrupted(InterruptReason reason) => CleanupChase();
private void CleanupChase()
{
if (_contactDamage != null)
_contactDamage.enabled = false;
_enemy.StopMovement();
}
}
}