← Cheatsheets
Tags: unity, navigation, navmesh, pathfinding, a-star, waypoints, obstacle-avoidance, game-dev
Last updated: 2026-06-27
Navigation & Pathfinding Cheatsheet
Quick Reference
| Approach | Best For | Complexity |
| Unity NavMesh | Built-in, baked static worlds | Low |
| Waypoint graph | Simple patrol routes | Low |
| A* grid | Custom tile/grid-based games | Medium |
| NavMesh + off-mesh links | Dynamic traversal (ladders, jumps) | Medium |
| NavMeshComponents | Runtime-baked NavMesh | High |
Unity NavMesh
Setup Checklist
- Mark static geometry as Navigation Static.
- Window → AI → Navigation → Bake tab → Bake.
- Add
NavMeshAgent component to moving NPC.
- Call
agent.SetDestination(target).
NavMeshAgent Properties
| Property | Description |
| Speed | Max movement speed (m/s) |
| Angular Speed | Rotation speed (deg/s) |
| Acceleration | Acceleration (m/s²) |
| Stopping Distance | Distance from target to stop |
| Auto Braking | Decelerate before reaching target |
| Radius | Agent radius for obstacle avoidance |
| Height | Agent height |
| Base Offset | Vertical offset from pivot |
| Obstacle Avoidance | None / Low / Medium / High Quality |
| Path Priority | Priority for path queue (0–99) |
| Auto Traverse Off-Mesh Links | Auto-use jump/ladder links |
| Auto Repath | Recalculate path if blocked |
Core API
NavMeshAgent agent = GetComponent<NavMeshAgent>();
agent.SetDestination(target.position); # Move to point
agent.destination = target.position; # Same as above
agent.ResetPath(); # Stop moving
agent.isStopped = true; # Pause movement
agent.remainingDistance; # Distance to target
agent.pathPending; # Is path computing?
agent.velocity; # Current velocity
agent.desiredVelocity; # Steering target velocity
# Check if reached
if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance)
// Reached destination
Path Status
NavMeshPath path = new NavMeshPath();
if (agent.CalculatePath(target.position, path)) {
if (path.status == NavMeshPathStatus.PathComplete) {
agent.SetPath(path);
} else if (path.status == NavMeshPathStatus.PathPartial) {
// Move to closest reachable point
}
}
NavMesh Baking
Area Types
| Area | Cost | Use Case |
| Walkable | 1.0 | Default ground |
| Not Walkable | — | Obstacles, walls |
| Jump | 2.0 | Off-mesh link areas |
| Water / Mud | 3.0+ | Slow movement areas |
| User 3–31 | Custom | Custom terrain costs |
# Sample area at position
NavMesh.SamplePosition(position, out NavMeshHit hit, 1f, NavMesh.AllAreas);
int areaMask = hit.mask;
bool isWalkable = (areaMask & 1) != 0;
Off-Mesh Links
# Manual traversal
IEnumerator TraverseLink() {
OffMeshLink link = GetComponent<OffMeshLink>();
agent.isStopped = true;
agent.updatePosition = false;
agent.updateRotation = false;
Vector3 start = link.startPos;
Vector3 end = link.endPos;
float t = 0;
while (t < 1f) {
t += Time.deltaTime * 2f;
transform.position = Vector3.Lerp(start, end, t);
yield return null;
}
agent.updatePosition = true;
agent.updateRotation = true;
agent.CompleteOffMeshLink();
}
Off-Mesh Link Types
| Type | Use Case |
| Auto-generated | Drop-down edges, jumps across gaps |
| Manual placement | Ladders, teleporters, ziplines |
| NavMeshLink (component) | Runtime links, procedural generation |
Waypoint System
public class WaypointPatrol : MonoBehaviour {
public Transform[] waypoints;
int index = 0;
NavMeshAgent agent;
void Start() { agent = GetComponent<NavMeshAgent>(); GoNext(); }
void Update() {
if (!agent.pathPending &&
agent.remainingDistance <= agent.stoppingDistance)
GoNext();
}
void GoNext() {
agent.SetDestination(waypoints[index].position);
index = (index + 1) % waypoints.Length;
}
}
Waypoint Patterns
| Pattern | Description |
| Loop | Cycle through all waypoints |
| Ping-Pong | Forward, then reverse back |
| Random | Pick random waypoint each time |
| Weighted Random | Favour nearby or “interesting” waypoints |
A* Pathfinding (Grid-Based)
Core Algorithm
List<Node> AStar(Node start, Node goal) {
var open = new PriorityQueue<Node, float>();
var closed = new HashSet<Node>();
start.gCost = 0; start.hCost = Heuristic(start, goal);
open.Enqueue(start, start.fCost);
while (open.Count > 0) {
Node current = open.Dequeue();
if (current == goal) return ReconstructPath(current);
closed.Add(current);
foreach (Node neighbor in current.Neighbors) {
if (closed.Contains(neighbor) || !neighbor.Walkable) continue;
float tentativeG = current.gCost + Distance(current, neighbor);
if (tentativeG < neighbor.gCost) {
neighbor.parent = current;
neighbor.gCost = tentativeG;
neighbor.hCost = Heuristic(neighbor, goal);
open.Enqueue(neighbor, neighbor.fCost);
}
}
}
return null;
}
Heuristic Functions
| Heuristic | Use Case |
| Manhattan | 4-directional grid (|dx| + |dy|) |
| Euclidean | Any-direction (sqrt(dx² + dy²)) |
| Diagonal | 8-directional grid (max(|dx|,|dy|)) |
| Weighted | Faster but suboptimal (h * weight > 1) |
Obstacle Avoidance
NavMeshObstacle
| Property | Description |
| Shape | Box or Capsule |
| Carve | Carve a hole in the NavMesh (static) |
| Carve Only Stationary | Only carve when not moving |
NavMeshObstacle obstacle = GetComponent<NavMeshObstacle>();
obstacle.enabled = true; # Carve hole, agents avoid
obstacle.enabled = false; # Remove hole, agents can pass
Local Avoidance (RVO)
- NavMeshAgent handles local avoidance automatically.
- Uses Reciprocal Velocity Obstacles (RVO).
- Priority: lower number = yields to higher priority agents.
NavMeshComponents (Runtime Baking)
NavMeshSurface surface = GetComponent<NavMeshSurface>();
surface.BuildNavMesh();
surface.layerMask = LayerMask.GetMask("Ground");
surface.useGeometry = NavMeshCollectGeometry.PhysicsColliders;
Performance Tips
- Bake NavMesh at largest agent radius needed.
- Use area costs instead of separate NavMeshes.
- Lower Obstacle Avoidance quality on background NPCs.
- Cache
NavMeshPath objects (reuse, don’t allocate per frame).
- Limit
agent.SetDestination() calls (don’t call every frame).
- Use
agent.autoRepath = false if you handle repath manually.