using UnityEngine; using UnityEngine.AI; [RequireComponent(typeof(NavMeshAgent))] public class NavMeshMovementController : MonoBehaviour { [Header("Movement")] public float stopDistanceTolerance = 0.1f; [Header("Rotation")] public bool enableSmartRotation = true; public float rotationSpeed = 10f; NavMeshAgent agent; Vector3 lastVelocity = Vector3.zero; Vector3? lookAtTarget = null; // Optional target to face when stopped void Awake() { agent = GetComponent(); if (agent != null) { agent.updateRotation = false; // We handle rotation manually } } void Update() { if (agent == null) return; // Update rotation based on movement direction if (enableSmartRotation) { Vector3 vel = agent.velocity; if (vel.sqrMagnitude > 0.01f) { // Moving - rotate toward movement direction Quaternion targetRot = Quaternion.LookRotation(vel.normalized); transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, rotationSpeed * Time.deltaTime); } else if (lookAtTarget.HasValue) { // Stopped - rotate toward look target if set Vector3 directionToTarget = (lookAtTarget.Value - transform.position).normalized; if (directionToTarget.sqrMagnitude > 0.01f) { directionToTarget.y = 0; // Keep rotation on horizontal plane Quaternion targetRot = Quaternion.LookRotation(directionToTarget); transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, rotationSpeed * Time.deltaTime); } } lastVelocity = vel; } // Auto-stop when reaching destination if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance + stopDistanceTolerance) { agent.isStopped = true; } } public void MoveTo(Vector3 worldPosition) { if (agent == null) return; agent.isStopped = false; agent.SetDestination(worldPosition); lookAtTarget = null; // Clear look target when starting new movement } public void MoveToAndLookAt(Vector3 worldPosition, Vector3 lookTarget) { if (agent == null) return; agent.isStopped = false; agent.SetDestination(worldPosition); lookAtTarget = lookTarget; // Set look target for when we arrive } public void Stop() { if (agent == null) return; agent.isStopped = true; } public void SetLookTarget(Vector3 target) { lookAtTarget = target; } public void ClearLookTarget() { lookAtTarget = null; } public bool IsAtDestination(float tolerance = 0.1f) { if (agent == null) return true; return !agent.pathPending && agent.remainingDistance <= agent.stoppingDistance + tolerance; } public Vector3 GetVelocity() => lastVelocity; public float GetSpeed() => agent != null ? agent.velocity.magnitude : 0f; }