104 lines
3.1 KiB
C#
104 lines
3.1 KiB
C#
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<NavMeshAgent>();
|
|
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;
|
|
}
|