2025-11-25 08:19:33 -05:00
/// ---------------------------------------------
/// 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 ( )
{
2025-12-08 05:27:53 -05:00
if ( m_Target = = null | | m_Target . Value = = null ) {
2025-11-25 08:19:33 -05:00
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 ;
}
2025-12-08 05:27:53 -05:00
2025-11-25 08:19:33 -05:00
/// <summary>
2025-12-08 05:27:53 -05:00
/// 任务结束时( 无论是成功到达, 还是被Parallel Selector打断) , 彻底重置状态
2025-11-25 08:19:33 -05:00
/// </summary>
public override void OnEnd ( )
{
base . OnEnd ( ) ;
2025-12-08 05:27:53 -05:00
if ( m_Pathfinder ! = null & & m_Pathfinder . m_NavMeshAgent ! = null )
2025-11-25 08:19:33 -05:00
{
2025-12-08 05:27:53 -05:00
// 1. 【核心修复】立即物理刹车
// 只有在 Agent 处于激活且在 NavMesh 上时才操作,防止报错
if ( m_Pathfinder . m_NavMeshAgent . isOnNavMesh & & m_Pathfinder . m_NavMeshAgent . isActiveAndEnabled )
{
// 强制停止寻路逻辑
m_Pathfinder . m_NavMeshAgent . isStopped = true ;
// 抹除物理惯性 (这是导致滑步的罪魁祸首)
m_Pathfinder . m_NavMeshAgent . velocity = Vector3 . zero ;
// 清空当前的路径数据 (防止下一个任务开始前, Agent试图跑完旧路径)
m_Pathfinder . m_NavMeshAgent . ResetPath ( ) ;
}
// 2. 恢复参数设置 (把 Agent 还原成标准状态,供下一个 Task 使用)
2025-11-25 08:19:33 -05:00
m_Pathfinder . m_NavMeshAgent . autoBraking = true ;
2025-12-08 05:27:53 -05:00
m_Pathfinder . m_NavMeshAgent . speed = m_OriginalMaxSpeed ;
// 注意:不要在这里设为 isStopped = false。
// 下一个 Task (比如 Attack 或 Move) 开始时,
// 它们会自动调用 SetDestination 或相关逻辑来启动 Agent。
// 在这里保持 Stopped 是最安全的“待机”状态。
2025-11-25 08:19:33 -05:00
}
}
}
}