Unity Term Book
Advanced Techniques

NavMesh

NavMesh (Navigation Mesh) is a walkable mesh baked from scene geometry so AI Agents can pathfind, avoid obstacles, and move automatically across the level.

Imagine...

A NavMesh is a road map for a 3D world. Before play, Unity "paints" walkable areas (blue) and blocked ones (walls, obstacles). When AI needs to go from A to B, it looks up that map and runs A-star for an optimal path — around walls, up stairs, away from cliffs. NavMeshAgent is the GPS driver on that map.

The concept in detail

NavMesh Baking: Unity analyzes static scene geometry (marked “Navigation Static”) into a walkable mesh. Key parameters: Agent Radius (minimum wall clearance — an agent cannot squeeze through a gap smaller than 2×radius), Agent Height (head height — no crawling under low ceilings), Max Slope (steepest climb), Step Height (max stair). Bake via Window → AI → Navigation → Bake.

NavMeshAgent sits on an NPC/AI and queries the NavMesh. Main API: agent.SetDestination(target) to start pathfinding; agent.remainingDistance for how far is left; agent.pathStatus (Complete/Partial/Invalid). speed, acceleration, stoppingDistance control motion.

NavMeshObstacle is a dynamic blocker — no rebake. Enable Carve to cut a hole in the NavMesh at runtime (more CPU), or disable Carve for avoidance only (agents go around, the mesh stays). Good for opening doors and moving vehicles.

For dynamic NavMesh (runtime rebake), use the NavMesh Components package (Unity-Technologies on GitHub) with NavMeshSurface — bake a region and update incrementally. Unity 6 folds multi-surface NavMesh into the built-in package.

NavMesh system pieces

🗺️

NavMesh

A walkable mesh baked from scene geometry. Static — does not change after bake.

Navigation Static flag
🤖

NavMeshAgent

Component on AI — queries a path, moves automatically, avoids other agents (avoidance).

SetDestination(target)
🚧

NavMeshObstacle

Dynamic obstacle — no rebake needed. Carve mode punches a hole in the NavMesh at runtime.

Carve = true/false

Hands-on steps

1

Mark static geometry

Select static meshes (walls, floors, platforms) → Inspector → Static dropdown → Navigation Static (and Contribute GI if you need lightmaps).

2

Bake the NavMesh

Window → AI → Navigation → Bake tab → tune Agent Radius/Height/Slope → Bake. A blue NavMesh appears in Scene view.

3

Add a NavMeshAgent to the NPC

Add Component → NavMeshAgent. Match Agent Size to bake settings. Disable Rigidbody gravity if present (the agent owns movement).

4

Set Destination from script

agent.SetDestination(target.position). Check agent.remainingDistance <= agent.stoppingDistance to know they arrived.

5

Add NavMeshObstacle for moving blockers

Add Component → NavMeshObstacle → Shape: Capsule/Box → enable Carve if the NavMesh must update live (doors, parked cars).

Interactive simulator

Click the map to set a destination — the Agent pathfinds across the NavMesh with A*.

Click to set destination
NavMesh Agent Obstacle Path

Code example

Basic

Simple NavMeshAgent AI — chase the player and stop at stopping distance.

using UnityEngine;
using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
  public Transform player;
  public float chaseRange   = 15f;
  public float attackRange  = 2f;
  public float updateRate   = 0.2f; // Recompute path every 0.2s

  NavMeshAgent agent;
  Animator anim;
  float nextUpdate;

  void Awake()
  {
      agent = GetComponent<NavMeshAgent>();
      anim  = GetComponent<Animator>();
  }

  void Update()
  {
      float dist = Vector3.Distance(transform.position, player.position);

      if (dist < chaseRange && Time.time >= nextUpdate)
      {
          nextUpdate = Time.time + updateRate;
          agent.SetDestination(player.position);
      }

      // Drive Animator from agent speed
      anim.SetFloat("Speed", agent.velocity.magnitude);

      if (dist < attackRange)
      {
          agent.ResetPath(); // Stop moving
          anim.SetTrigger("Attack");
      }
  }
}

Code example

Advanced

Patrol AI on a NavMesh — waypoint loop plus player detection.

using UnityEngine;
using UnityEngine.AI;

public class PatrolAI : MonoBehaviour
{
  public Transform[] waypoints;
  public float detectRange = 8f;
  public Transform player;

  NavMeshAgent agent;
  int current = 0;
  enum State { Patrol, Chase, Investigate }
  State state = State.Patrol;

  void Awake() => agent = GetComponent<NavMeshAgent>();

  void Start() => GotoNextWaypoint();

  void Update()
  {
      float dist = Vector3.Distance(transform.position, player.position);

      switch (state)
      {
          case State.Patrol:
              if (dist < detectRange) { state = State.Chase; break; }
              if (!agent.pathPending && agent.remainingDistance < 0.5f)
                  GotoNextWaypoint();
              break;

          case State.Chase:
              agent.SetDestination(player.position);
              if (dist > detectRange * 1.5f)
                  state = State.Investigate;
              break;

          case State.Investigate:
              if (!agent.pathPending && agent.remainingDistance < 0.5f)
              { state = State.Patrol; GotoNextWaypoint(); }
              break;
      }
  }

  void GotoNextWaypoint()
  {
      if (waypoints.Length == 0) return;
      agent.SetDestination(waypoints[current].position);
      current = (current + 1) % waypoints.Length;
  }
}

📌 Quick recap

  • NavMesh = walkable map, baked from static geometry
  • SetDestination() every frame is expensive — throttle with a coroutine
  • remainingDistance: leftover path length
  • NavMeshObstacle + Carve = a runtime hole
  • Disable Rigidbody.gravity when using NavMeshAgent

⚠️ Common mistakes

  • ❌ The Agent does not move even though SetDestination is correct

    The destination is off the NavMesh, or the NavMesh was never baked

    ✅ Use NavMesh.SamplePosition() to find the nearest point on the mesh

  • ❌ The Agent walks through walls or gets stuck

    Agent Radius on NavMeshAgent is smaller than the bake radius

    ✅ Match NavMeshAgent Agent Radius to the bake Agent Radius