using UnityEngine;
using UnityEngine.AI;
namespace BehaviorDesigner.Runtime.Tasks.Movement
{
public abstract class NavMeshMovement : Movement
{
[Tooltip("The speed of the agent")]
[UnityEngine.Serialization.FormerlySerializedAs("speed")]
public SharedFloat m_Speed = 10;
[Tooltip("The angular speed of the agent")]
[UnityEngine.Serialization.FormerlySerializedAs("angularSpeed")]
public SharedFloat m_AngularSpeed = 120;
[Tooltip("The agent has arrived when the destination is less than the specified amount. This distance should be greater than or equal to the NavMeshAgent StoppingDistance.")]
[UnityEngine.Serialization.FormerlySerializedAs("arriveDistance")]
public SharedFloat m_ArriveDistance = 0.2f;
[Tooltip("Should the NavMeshAgent be stopped when the task ends?")]
[UnityEngine.Serialization.FormerlySerializedAs("stopOnTaskEnd")]
public SharedBool m_StopOnTaskEnd = true;
[Tooltip("Should the NavMeshAgent rotation be updated when the task ends?")]
[UnityEngine.Serialization.FormerlySerializedAs("updateRotation")]
public SharedBool m_UpdateRotation = true;
// Component references
protected NavMeshAgent m_NavMeshAgent;
private bool m_StartUpdateRotation;
///
/// Cache the component references.
///
public override void OnAwake()
{
m_NavMeshAgent = GetComponent();
}
///
/// Allow pathfinding to resume.
///
public override void OnStart()
{
m_NavMeshAgent.speed = m_Speed.Value;
m_NavMeshAgent.angularSpeed = m_AngularSpeed.Value;
m_NavMeshAgent.isStopped = false;
m_StartUpdateRotation = m_NavMeshAgent.updateRotation;
UpdateRotation(m_UpdateRotation.Value);
}
///
/// Set a new pathfinding destination.
///
/// The destination to set.
/// True if the destination is valid.
protected override bool SetDestination(Vector3 destination)
{
m_NavMeshAgent.isStopped = false;
return m_NavMeshAgent.SetDestination(destination);
}
///
/// Specifies if the rotation should be updated.
///
/// Should the rotation be updated?
protected override void UpdateRotation(bool update)
{
m_NavMeshAgent.updateRotation = update;
m_NavMeshAgent.updateUpAxis = update;
}
///
/// Does the agent have a pathfinding path?
///
/// True if the agent has a pathfinding path.
protected override bool HasPath()
{
return m_NavMeshAgent.hasPath && m_NavMeshAgent.remainingDistance > m_ArriveDistance.Value;
}
///
/// Returns the velocity of the agent.
///
/// The velocity of the agent.
protected override Vector3 Velocity()
{
return m_NavMeshAgent.velocity;
}
///
/// Returns true if the position is a valid pathfinding position.
///
/// The position to sample. The position will be updated to the valid sampled position.
/// True if the position is a valid pathfinding position.
protected bool SamplePosition(ref Vector3 position)
{
NavMeshHit hit;
if (NavMesh.SamplePosition(position, out hit, m_NavMeshAgent.height * 2, NavMesh.AllAreas)) {
position = hit.position;
return true;
}
return false;
}
///
/// Has the agent arrived at the destination?
///
/// True if the agent has arrived at the destination.
protected override bool HasArrived()
{
// The path hasn't been computed yet if the path is pending.
float remainingDistance;
if (m_NavMeshAgent.pathPending) {
remainingDistance = float.PositiveInfinity;
} else {
remainingDistance = m_NavMeshAgent.remainingDistance;
}
return remainingDistance <= m_ArriveDistance.Value;
}
///
/// Stop pathfinding.
///
protected override void Stop()
{
UpdateRotation(m_StartUpdateRotation);
if (m_NavMeshAgent.hasPath) {
m_NavMeshAgent.isStopped = true;
}
}
///
/// The task has ended. Stop moving.
///
public override void OnEnd()
{
if (m_StopOnTaskEnd.Value) {
Stop();
} else {
UpdateRotation(m_StartUpdateRotation);
}
}
///
/// The behavior tree has ended. Stop moving.
///
public override void OnBehaviorComplete()
{
Stop();
}
///
/// Reset the values back to their defaults.
///
public override void OnReset()
{
m_Speed = 10;
m_AngularSpeed = 120;
m_ArriveDistance = 1;
m_StopOnTaskEnd = true;
}
}
}