NavMesh in Depth
Tell Unity where characters can walk, give them a destination, and let them find their own way around walls.
A NavMesh is a map of footpaths drawn over your level. An agent is a person holding that map. You point at a spot and say "go there"; the person plans a route and walks it, stepping around other people on the way. The map doesn't decide where to go. That's your game's job.
Install AI Navigation (com.unity.ai.navigation) from the Package Manager. Scripts need using UnityEngine.AI;.
The pieces
| Component | Job |
|---|---|
| NavMeshSurface | Looks at your level and bakes (builds) the walkable map. |
| NavMeshAgent | Goes on the character. Plans routes and walks them. |
| NavMeshObstacle | Something agents should avoid, like a crate or a closed door. |
| NavMeshLink | A shortcut between two areas that aren't connected, like a jump across a gap. |
1. Bake a walkable map
- Build a floor and some walls (they need colliders or meshes). Leave a doorway.
- Create an empty object called Level, add NavMeshSurface and click Bake.
- A blue overlay appears on the floor. That's the walkable area. Check the doorway is blue too.
The blue area stops a little short of walls. That gap is the agent's Radius: room for its body. If a doorway disappears, the agent is too wide for it. Change the radius in the agent settings and bake again.
2. Walk to a target
Add a NavMeshAgent to your character, place it on the blue area, then attach this script and drag a target object into Target.
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
public class FollowTarget : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float repathDelay = 0.25f; // seconds between route updates
private NavMeshAgent agent;
private float nextRepath;
void Awake() => agent = GetComponent<NavMeshAgent>();
void Update()
{
if (target == null || !agent.isOnNavMesh) return;
// Don't plan a new route every frame: a few times a second is plenty
if (Time.time >= nextRepath)
{
nextRepath = Time.time + repathDelay;
agent.SetDestination(target.position);
}
// Once planning is done, find out whether the target is reachable
if (!agent.pathPending)
CanReach = agent.pathStatus == NavMeshPathStatus.PathComplete;
}
public bool CanReach { get; private set; }
}
Press Play and move the target around in the Scene view. The character should follow, going through the doorway instead of into walls.
Did it arrive? Can it get there?
| Check | Meaning |
|---|---|
agent.pathPending | Still planning. Wait. |
pathStatus == PathComplete | A full route exists. |
pathStatus == PathPartial | It can only get close, e.g. the target is in a sealed room. |
remainingDistance <= stoppingDistance | Arrived (only meaningful once pathPending is false). |
Agent settings worth knowing
| Setting | What it does |
|---|---|
| Speed / Acceleration | Top speed and how fast it gets there. |
| Angular Speed | How fast it turns. |
| Stopping Distance | How close counts as "arrived". Useful for melee range. |
| Auto Braking | Slow down near the end. Turn off for smooth patrols. |
To animate, feed agent.velocity.magnitude into your Animator's speed parameter.
Doors, obstacles and jumps
- Moving obstacles (a rolling barrel): add NavMeshObstacle. Agents steer around it.
- Things that block a path (a closed door): also tick Carve. It cuts a hole in the map so agents plan a route around it. Untick when the door opens.
- Gaps and ledges: add a NavMeshLink between the two sides. The agent will use it as part of its route.
- Teleporting an agent: use
agent.Warp(position), nottransform.position.
Troubleshooting
| Problem | Check |
|---|---|
| "Agent is not on a NavMesh" | Did you bake? Is the character standing on the blue area? |
| Won't go through a door | Is the doorway blue? If not, the agent radius is too big. |
| Stops short | Stopping Distance too high, or the target is off the blue area. |
| Jitters | Something else (Rigidbody, animation, another script) is also moving it. |
Common Mistakes
- Calling
SetDestinationevery frame for a hundred enemies. Update a few times a second instead. - Reading
remainingDistancewhilepathPendingis true. It isn't ready yet. - Only testing targets that can be reached. Also try one in a sealed room.
- Moving level geometry and forgetting to re-bake.
See also
- Simple State Machines (patrol / chase / attack)
- Working with CharacterController
- Animator
This page is a simplified, AI-assisted interpretation. For the complete and authoritative reference, see the official documentation.