175 lines
7.3 KiB
C#
175 lines
7.3 KiB
C#
/// ---------------------------------------------
|
|
/// Movement Pack for Behavior Designer Pro
|
|
/// Copyright (c) Opsive. All Rights Reserved.
|
|
/// https://www.opsive.com
|
|
/// ---------------------------------------------
|
|
|
|
using Opsive.BehaviorDesigner.AddOns.Shared.Runtime.Pathfinding;
|
|
|
|
namespace Opsive.BehaviorDesigner.AddOns.MovementPack.Runtime.Tasks
|
|
{
|
|
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
|
using Opsive.GraphDesigner.Runtime;
|
|
using Opsive.GraphDesigner.Runtime.Variables;
|
|
using UnityEngine;
|
|
|
|
[Opsive.Shared.Utility.Description("Pursues the specified target with precise stopping. Manually controls agent speed based on distance to stop smoothly without overshooting.")]
|
|
[NodeIcon("079b135d5d495e14abd9ad2cb0dfaf9e", "c0515b66e6314734ba5a8f2ec7d6f451")]
|
|
public class PrecisePursue : MovementBase // 依然继承自 MovementBase
|
|
{
|
|
// --- 原有的 Pursue 变量 ---
|
|
[Tooltip("The GameObject that the agent is seeking.")]
|
|
[SerializeField] protected SharedVariable<GameObject> m_Target;
|
|
[Tooltip("Specifies how far to predict the distance ahead of the target. Lower values indicate that less distance should be predicated.")]
|
|
[SerializeField] protected SharedVariable<float> m_DistancePrediction = 20;
|
|
[Tooltip("Specifies the multiplier for predicting the look ahead distance.")]
|
|
[SerializeField] protected SharedVariable<float> m_DistancePredictionMultiplier = 20;
|
|
|
|
// --- 新增的“方案一”变量 ---
|
|
[Header("Precise Stopping")]
|
|
[Tooltip("【新】开始减速的距离 (例如 6m)")]
|
|
[SerializeField] protected SharedVariable<float> m_SlowDownDistance = 6f;
|
|
[Tooltip("【新】减速到最慢时的速度 (防止完全停止)")]
|
|
[SerializeField] protected SharedVariable<float> m_MinSpeed = 0.5f;
|
|
|
|
// --- 私有变量 ---
|
|
private Vector3 m_TargetPosition;
|
|
private float m_OriginalMaxSpeed; // 用于存储 Agent 的原始最大速度
|
|
private NavMeshAgentPathfinder m_Pathfinder => base.m_Pathfinder as NavMeshAgentPathfinder;
|
|
|
|
/// <summary>
|
|
/// The task has started.
|
|
/// </summary>
|
|
public override void OnStart()
|
|
{
|
|
base.OnStart();
|
|
|
|
if (m_Target == null) {
|
|
Debug.LogError("Error: A target must be set on the PrecisePursue ability.");
|
|
return;
|
|
}
|
|
|
|
// --- 关键设置 ---
|
|
// 1. 存储原始最大速度
|
|
m_OriginalMaxSpeed = m_Pathfinder.Speed;
|
|
|
|
// 2. 关闭 NavMeshAgent 的自动刹车,因为我们要手动控制
|
|
m_Pathfinder.m_NavMeshAgent.autoBraking = false;
|
|
// ---------------
|
|
|
|
m_TargetPosition = m_Target.Value.transform.position;
|
|
SetDestination(GetTargetDestination());
|
|
}
|
|
|
|
/// <summary>
|
|
/// (原 Pursue 脚本逻辑,保持不变)
|
|
/// Returns the target destination.
|
|
/// </summary>
|
|
/// <returns>The target destination.</returns>
|
|
private Vector3 GetTargetDestination()
|
|
{
|
|
// Calculate the current distance to the target and the current speed.
|
|
var distance = (m_Target.Value.transform.position - transform.position).magnitude;
|
|
var velocityMagnitude = m_Pathfinder.Velocity.magnitude;
|
|
|
|
var futurePrediction = 0f;
|
|
// Set the future prediction to the max prediction if the speed is too small to give an accurate prediction.
|
|
if (velocityMagnitude <= distance / m_DistancePrediction.Value) {
|
|
futurePrediction = m_DistancePrediction.Value;
|
|
} else {
|
|
futurePrediction = (distance / velocityMagnitude) * m_DistancePredictionMultiplier.Value;
|
|
}
|
|
|
|
// Predict the future by taking the velocity of the target and multiply it by the future prediction.
|
|
var lastTargetPosition = m_TargetPosition;
|
|
m_TargetPosition = m_Target.Value.transform.position;
|
|
return m_TargetPosition + (m_TargetPosition - lastTargetPosition) * futurePrediction;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the destination.
|
|
/// </summary>
|
|
/// <returns>Success when the agent arrives.</returns>
|
|
public override TaskStatus OnUpdate()
|
|
{
|
|
if (m_Target.Value == null) {
|
|
return TaskStatus.Failure;
|
|
}
|
|
|
|
// --- 核心修改:基于距离的速度控制 ---
|
|
|
|
// 1. 计算【直线距离】(非常重要,不用 NavMesh 的 remainingDistance)
|
|
float distanceToTarget = Vector3.Distance(transform.position, m_Target.Value.transform.position);
|
|
|
|
// 2. 检查是否已“到达” (即进入了停止范围)
|
|
if (distanceToTarget <= m_Pathfinder.StoppingDistance)
|
|
{
|
|
// 已经到达,强制停止并返回成功
|
|
m_Pathfinder.m_NavMeshAgent.velocity = Vector3.zero; // 清除惯性
|
|
m_Pathfinder.m_NavMeshAgent.isStopped = true;
|
|
m_Pathfinder.m_NavMeshAgent.speed = 0f; // 速度设为零
|
|
return TaskStatus.Success;
|
|
}
|
|
|
|
// 3. 检查是否在“减速缓冲区”
|
|
if (distanceToTarget < m_SlowDownDistance.Value)
|
|
{
|
|
// 在缓冲区 (例如 2m 到 6m 之间)
|
|
// 计算减速因子 (0.0 -> 1.0)
|
|
// 距离 = 2m 时, factor = 0.0
|
|
// 距离 = 6m 时, factor = 1.0
|
|
float factor = (distanceToTarget - m_Pathfinder.StoppingDistance) / (m_SlowDownDistance.Value - m_Pathfinder.StoppingDistance);
|
|
|
|
// 使用 Lerp 平滑地插值速度
|
|
m_Pathfinder.m_NavMeshAgent.speed = Mathf.Lerp(m_MinSpeed.Value, m_OriginalMaxSpeed, factor);
|
|
m_Pathfinder.m_NavMeshAgent.isStopped = false;
|
|
}
|
|
else
|
|
{
|
|
// 在缓冲区外,全速前进
|
|
m_Pathfinder.m_NavMeshAgent.speed = m_OriginalMaxSpeed;
|
|
m_Pathfinder.m_NavMeshAgent.isStopped = false;
|
|
}
|
|
// --- 核心修改结束 ---
|
|
|
|
|
|
// 4. (原 Pursue 逻辑) 持续更新目标点(因为目标在移动)
|
|
SetDestination(GetTargetDestination());
|
|
|
|
return TaskStatus.Running;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the task values back to their default.
|
|
/// </summary>
|
|
public override void Reset()
|
|
{
|
|
base.Reset();
|
|
|
|
// 原有变量
|
|
m_Target = null;
|
|
m_DistancePrediction = 20;
|
|
m_DistancePredictionMultiplier = 20;
|
|
|
|
// 新增变量
|
|
m_SlowDownDistance = 6f;
|
|
m_MinSpeed = 0.5f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 任务结束时,重置 NavMeshAgent 的状态
|
|
/// </summary>
|
|
public override void OnEnd()
|
|
{
|
|
base.OnEnd();
|
|
|
|
// 恢复 Agent 的默认设置,这非常重要!
|
|
if (m_Pathfinder != null)
|
|
{
|
|
m_Pathfinder.m_NavMeshAgent.autoBraking = true;
|
|
m_Pathfinder.m_NavMeshAgent.speed = m_OriginalMaxSpeed;
|
|
m_Pathfinder.m_NavMeshAgent.isStopped = false;
|
|
}
|
|
}
|
|
}
|
|
} |