# Unity Navigation (NavMesh, Pathfinding, AI) ## Overview Unity's AI Navigation package (`com.unity.ai.navigation`) bakes a **NavMesh** -- a simplified walkable surface -- and provides `NavMeshAgent` to move characters along it. This is the standard solution for AI NPCs in the generated project. ## Baking a NavMesh 1. Mark static colliders as **Navigation Static** (Window > AI > Navigation > Object). 2. Bake the NavMesh (Window > AI > Navigation > Bake). 3. At runtime, every `NavMeshAgent` on the scene automatically walks on the baked NavMesh. > For a procedurally generated city, baking at design time is impossible. > Either: > * Bake at runtime via `NavMeshSurface.BuildNavMesh()` (AI Navigation > package), or > * Use the simpler approach in `NPCController.cs`: pick random points via > `NavMesh.SamplePosition` so the agent always lands on a valid walkable > spot. ## NavMeshAgent ```csharp [RequireComponent(typeof(NavMeshAgent))] public class NPCController : MonoBehaviour { private NavMeshAgent _agent; private void Awake() => _agent = GetComponent(); private void Start() { PickNewDestination(); } private void PickNewDestination() { Vector3 random = transform.position + Random.insideUnitSphere * 20f; if (NavMesh.SamplePosition(random, out NavMeshHit hit, 20f, NavMesh.AllAreas)) _agent.SetDestination(hit.position); } } ``` Key properties: | Property | Meaning | |---------------------|------------------------------------------------------------| | `speed` | Max movement speed (m/s) | | `angularSpeed` | Max turning speed (deg/s) | | `acceleration` | How quickly the agent reaches `speed` | | `stoppingDistance` | Distance at which the agent considers the destination reached | | `autoBraking` | Whether to slow down near the destination | | `isStopped` | Pause the agent without clearing the path | | `remainingDistance` | Distance to the end of the current path | | `pathPending` | True while a new path is still being computed | ## State machines for AI A common pattern is a small finite state machine: ``` Idle --(timer)--> Wander --(player in range)--> Chase ^ | | | (lost sight) +---------------------------------+ +--------------------+ ``` The generated `NPCController.cs` implements exactly this pattern with three states (`Idle`, `Wander`, `Chase`) and switch-based dispatch in `Update()`. ## Pathfinding details * `NavMeshAgent.SetDestination(target)` is async -- the path may not be ready on the same frame. Check `!agent.pathPending` before reading `remainingDistance`. * `agent.pathStatus` tells you whether a path is `PathComplete`, `PathPartial` or `PathInvalid`. * `NavMesh.CalculatePath(source, target, mask, out path)` lets you compute a path without an agent (useful for "can the NPC reach this point?" checks). ## NavMeshObstacle For dynamic obstacles (a car parked across a road, a door that closes), add a `NavMeshObstacle` component. Set `carve = true` to actually cut a hole in the NavMesh; otherwise the obstacle only pushes agents around. ## Off-mesh links When the walkable surface is disconnected (e.g. a gap between rooftops), drop an `OffMeshLink` to let agents jump or teleport across. You can also use them for ladders, climbing walls, and jumping down from ledges. ## Performance * Keep the agent count under ~100 simultaneous active agents on desktop. * For larger crowds use the **ECS/DOTS navigation** solutions or batch pathfinding across frames. * Set `agent.autoRepath = false` if you do not need the agent to follow moving targets, and call `SetDestination` less often (e.g. every 0.5 s).