AI/ActionSystem/BehaviorTree/Nodes/FollowTargetNode.cs
namespace HC3;
/// <summary>
/// A node that makes an agent follow a target until it is close enough.
/// It supports repathing if the target moves significantly.
/// </summary>
public sealed class FollowTargetNode : Node
{
private readonly Agent _agent;
private readonly GameObject _target;
private readonly float _requiredDistance;
private readonly float _repathDistance;
private readonly string _reason;
private Vector3 _lastTargetPosition;
public FollowTargetNode( Agent agent, GameObject target, float distance, float repath, string reason )
{
_agent = agent;
_target = target;
_requiredDistance = distance;
_repathDistance = repath;
_reason = reason;
}
protected override void OnStart()
{
_lastTargetPosition = _target.WorldPosition;
_agent.Controller.Navigate( _lastTargetPosition );
}
public override Status Tick()
{
if ( !_target.IsValid() )
return Status.Failure;
// Check if target has moved significantly
float distanceToTarget = _agent.WorldPosition.Distance( _target.WorldPosition );
float targetMovement = _lastTargetPosition.Distance( _target.WorldPosition );
// Repath if target has moved significantly
if ( targetMovement > _repathDistance / 2 )
{
_lastTargetPosition = _target.WorldPosition;
_agent.Controller.Navigate( _lastTargetPosition );
}
// Continue pursuing if we're too far
if ( distanceToTarget > _requiredDistance )
{
// If we're not navigating for some reason, restart navigation
if ( !_agent.Controller.IsNavigating )
{
_agent.Controller.Navigate( _target.WorldPosition );
}
return Status.Running;
}
// We're close enough to the target
_agent.Controller.ClearNavigation();
return Status.Success;
}
public override ActionDisplayInfo? GetDisplay()
{
return new ActionDisplayInfo(
"pest_control",
_reason,
_agent.Controller.GetPathProgress()
);
}
}