#if GRAPH_DESIGNER using UnityEngine; using Opsive.BehaviorDesigner.Runtime.Tasks; using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; using BaseGames.Enemies; using BaseGames.Enemies.Abilities; namespace BaseGames.Enemies.AI { /// /// BD Action:等待指定能力执行结束后返回 Success。 /// 适用于需要同步等待某个由外部触发的能力(而非本节点触发)的场景。 /// /// 返回 Running:能力正在执行。 /// 返回 Success:能力执行完毕(IsRunning = false)。 /// 返回 Failure:能力不存在,或超时保护触发。 /// /// 典型用法:Sequence [ BD_UseAbility(A) → BD_WaitUntilAbilityEnd(B) ] 等待 B 被 A 内部链式触发后结束。 /// [TaskName("Wait Until Ability End")] [TaskCategory("BaseGames/Enemy/Combat")] [TaskDescription("等待指定能力执行完成后返回 Success")] public sealed class BD_WaitUntilAbilityEnd : Action { [Tooltip("可直接拖拽 EnemyAbilitySO 资产(推荐),或填写裸字符串 ID 作为兜底")] [SerializeField] private EnemyAbilitySO m_AbilitySO; [SerializeField] private string m_AbilityId = ""; [Tooltip("超时保护(秒);0 = 永不超时")] [SerializeField, Min(0f)] private float m_Timeout = 5f; private EnemyBase _enemy; private EnemyAbilityBase _ability; private float _deadline; public override void OnAwake() => _enemy = GetComponent(); public override void OnStart() { _ability = null; _deadline = m_Timeout > 0f ? Time.time + m_Timeout : float.MaxValue; if (_enemy == null) return; string id = m_AbilitySO != null ? m_AbilitySO.abilityId : m_AbilityId; if (!string.IsNullOrEmpty(id)) _ability = _enemy.Abilities?.Get(id); } public override TaskStatus OnUpdate() { if (_ability == null) return TaskStatus.Failure; if (Time.time >= _deadline) { Debug.LogWarning($"[BD_WaitUntilAbilityEnd] 能力 '{_ability.Config?.abilityId}' 超时,强制中断", gameObject); // 强制中断仍在运行的能力,防止 HitBox/动画协程泄漏 if (_ability.IsRunning) _ability.Interrupt(InterruptReason.ExternalRequest); return TaskStatus.Failure; } return _ability.IsRunning ? TaskStatus.Running : TaskStatus.Success; } public override void OnEnd() => _ability = null; } } #endif