Part of these game systems:
NavMesh Click-to-Move
Click-to-move character controller using NavMeshAgent. Click anywhere to navigate, with destination marker and path line.
How to Use
1
Add a NavMeshAgent component to your character
2
Attach NavMeshClickToMove
3
Bake a NavMesh on your ground/terrain
4
Right-click (configurable) to move to a destination
5
Optionally assign a destination marker prefab (particle, ring, etc.)
6
Path line shows the navigation route in cyan
Source Code
C#
using UnityEngine;
using UnityEngine.AI;
/// <summary>
/// Click-to-move controller using NavMeshAgent.
/// Click on the ground to navigate. Optionally shows path and destination marker.
/// </summary>
[RequireComponent(typeof(NavMeshAgent))]
public class NavMeshClickToMove : MonoBehaviour
{
[Header("Input")]
[SerializeField] private int mouseButton = 1; // Right-click
[SerializeField] private LayerMask groundLayer = ~0;
[Header("Visual Feedback")]
[SerializeField] private GameObject destinationMarkerPrefab;
[SerializeField] private bool showPathLine = true;
[SerializeField] private Color pathColor = Color.cyan;
[Header("Movement")]
[SerializeField] private float stoppingDistance = 0.5f;
[SerializeField] private float moveSpeed = 5f;
private NavMeshAgent agent;
private LineRenderer pathLine;
private GameObject activeMarker;
private Camera mainCamera;
private void Awake()
{
agent = GetComponent<NavMeshAgent>();
agent.speed = moveSpeed;
agent.stoppingDistance = stoppingDistance;
if (showPathLine)
{
pathLine = gameObject.AddComponent<LineRenderer>();
pathLine.startWidth = 0.05f;
pathLine.endWidth = 0.05f;
pathLine.material = new Material(Shader.Find("Sprites/Default"));
pathLine.startColor = pathColor;
pathLine.endColor = pathColor;
pathLine.positionCount = 0;
}
}
private void Start()
{
mainCamera = Camera.main;
}
private void Update()
{
if (Input.GetMouseButtonDown(mouseButton))
{
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 100f, groundLayer))
{
MoveTo(hit.point);
}
}
UpdatePathLine();
UpdateMarker();
}
/// <summary>
/// Move to a world position via NavMesh.
/// </summary>
public void MoveTo(Vector3 destination)
{
if (NavMesh.SamplePosition(destination, out NavMeshHit navHit, 2f, NavMesh.AllAreas))
{
agent.SetDestination(navHit.position);
ShowMarker(navHit.position);
}
}
/// <summary>
/// Stop moving and clear the path.
/// </summary>
public void Stop()
{
agent.ResetPath();
HideMarker();
}
private void ShowMarker(Vector3 position)
{
if (destinationMarkerPrefab == null) return;
if (activeMarker == null)
activeMarker = Instantiate(destinationMarkerPrefab);
activeMarker.transform.position = position + Vector3.up * 0.05f;
activeMarker.SetActive(true);
}
private void HideMarker()
{
if (activeMarker != null)
activeMarker.SetActive(false);
}
private void UpdateMarker()
{
if (activeMarker != null && activeMarker.activeSelf)
{
if (!agent.hasPath || agent.remainingDistance <= stoppingDistance)
HideMarker();
}
}
private void UpdatePathLine()
{
if (pathLine == null) return;
if (agent.hasPath && agent.path.corners.Length > 1)
{
pathLine.positionCount = agent.path.corners.Length;
pathLine.SetPositions(agent.path.corners);
}
else
{
pathLine.positionCount = 0;
}
}
}