#if GRAPH_DESIGNER using Opsive.BehaviorDesigner.Runtime.Tasks; using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; using UnityEngine; namespace BaseGames.Enemies.AI { /// /// BD Action:战斗站位控制。 /// 在 [m_PreferredMinDist, m_PreferredMaxDist] 范围内保持与玩家的水平距离: /// - 距离过近 → 后退 /// - 距离过远 → 靠近 /// - 在范围内 → 停止移动,持续朝向玩家 /// 始终返回 Running,上层 BT 通过 Abort 或条件终止该 Task。 /// [TaskName("Maintain Combat Distance")] [TaskCategory("BaseGames/Enemy/Combat")] [TaskDescription("在战斗中维持与目标的理想距离范围")] public class BD_MaintainCombatDistance : Action { [Tooltip("期望最小距离(m);小于此值开始后退")] [SerializeField] private float m_PreferredMinDist = 2f; [Tooltip("期望最大距离(m);大于此值开始靠近")] [SerializeField] private float m_PreferredMaxDist = 4f; [Tooltip("后退速度(m/s),默认使用 WalkSpeed")] [SerializeField] private float m_BackpedaleSpeed = 0f; [Tooltip("每帧重新规划路径的阈值(m);玩家移动超过此距离才重规划,降低频率")] [SerializeField] private float m_ReplanThreshold = 0.5f; private EnemyBase _enemy; private Vector2 _lastPlayerPos; private float _sqrMin; private float _sqrMax; public override void OnAwake() => _enemy = GetComponent(); public override void OnStart() { _sqrMin = m_PreferredMinDist * m_PreferredMinDist; _sqrMax = m_PreferredMaxDist * m_PreferredMaxDist; _lastPlayerPos = Vector2.positiveInfinity; } public override TaskStatus OnUpdate() { if (_enemy == null || _enemy.PlayerTransform == null) return TaskStatus.Failure; if (_enemy.Stats == null) return TaskStatus.Failure; _enemy.FacePlayer(); float sqrDist = _enemy.Stats.SqrDistanceToPlayer; if (sqrDist < _sqrMin) { // 距离过近 → 后退(向远离玩家方向移动) _enemy.Nav?.StopNavigation(); Vector2 toPlayer = ((Vector2)_enemy.PlayerTransform.position - (Vector2)_enemy.transform.position).normalized; float backDir = -Mathf.Sign(toPlayer.x); float speed = m_BackpedaleSpeed > 0f ? m_BackpedaleSpeed : _enemy.Stats.WalkSpeed; _enemy.Movement?.MoveWithSpeed(backDir, speed); } else if (sqrDist > _sqrMax) { // 距离过远 → 靠近 Vector2 playerPos = _enemy.PlayerTransform.position; float moved = ((Vector2)playerPos - _lastPlayerPos).sqrMagnitude; if (moved > m_ReplanThreshold * m_ReplanThreshold) { _lastPlayerPos = playerPos; _enemy.MoveTo(playerPos); } } else { // 在最优范围内 → 停止导航,原地保持朝向 _enemy.Nav?.StopNavigation(); _enemy.Movement?.StopHorizontal(); } return TaskStatus.Running; } public override void OnEnd() { _enemy?.Movement?.StopHorizontal(); _enemy?.Nav?.StopNavigation(); } } } #endif