#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