using UnityEngine; using UnityEngine.AI; namespace BehaviorDesigner.Runtime.Tasks.Movement { public abstract class NavMeshMovement : Movement { [Tooltip("The speed of the agent")] public SharedFloat speed = 10; [Tooltip("The angular speed of the agent")] public SharedFloat 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.")] public SharedFloat arriveDistance = 0.2f; [Tooltip("Should the NavMeshAgent be stopped when the task ends?")] public SharedBool stopOnTaskEnd = true; [Tooltip("Should the NavMeshAgent rotation be updated when the task ends?")] public SharedBool updateRotation = true; // Component references protected NavMeshAgent navMeshAgent; private bool startUpdateRotation; /// /// Cache the component references. /// public override void OnAwake() { navMeshAgent = GetComponent(); } /// /// Allow pathfinding to resume. /// public override void OnStart() { navMeshAgent.speed = speed.Value; navMeshAgent.angularSpeed = angularSpeed.Value; navMeshAgent.isStopped = false; startUpdateRotation = navMeshAgent.updateRotation; UpdateRotation(updateRotation.Value); } /// /// Set a new pathfinding destination. /// /// The destination to set. /// True if the destination is valid. protected override bool SetDestination(Vector3 destination) { navMeshAgent.isStopped = false; return navMeshAgent.SetDestination(destination); } /// /// Specifies if the rotation should be updated. /// /// Should the rotation be updated? protected override void UpdateRotation(bool update) { navMeshAgent.updateRotation = update; navMeshAgent.updateUpAxis = update; } /// /// Does the agent have a pathfinding path? /// /// True if the agent has a pathfinding path. protected override bool HasPath() { return navMeshAgent.hasPath && navMeshAgent.remainingDistance > arriveDistance.Value; } /// /// Returns the velocity of the agent. /// /// The velocity of the agent. protected override Vector3 Velocity() { return navMeshAgent.velocity; } /// /// Returns true if the position is a valid pathfinding position. /// /// The position to sample. /// True if the position is a valid pathfinding position. protected bool SamplePosition(Vector3 position) { NavMeshHit hit; return NavMesh.SamplePosition(position, out hit, navMeshAgent.height * 2, NavMesh.AllAreas); } /// /// 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 (navMeshAgent.pathPending) { remainingDistance = float.PositiveInfinity; } else { remainingDistance = navMeshAgent.remainingDistance; } return remainingDistance <= arriveDistance.Value; } /// /// Stop pathfinding. /// protected override void Stop() { UpdateRotation(startUpdateRotation); if (navMeshAgent.hasPath) { navMeshAgent.isStopped = true; } } /// /// The task has ended. Stop moving. /// public override void OnEnd() { if (stopOnTaskEnd.Value) { Stop(); } else { UpdateRotation(startUpdateRotation); } } /// /// The behavior tree has ended. Stop moving. /// public override void OnBehaviorComplete() { Stop(); } /// /// Reset the values back to their defaults. /// public override void OnReset() { speed = 10; angularSpeed = 120; arriveDistance = 1; stopOnTaskEnd = true; } } }