PathFinder Manual
Version 1.0.0
PathFinder is a complete pathfinding solution for Unity: several graph types, a multithreaded A* core, path post-processing, ready to use movement components and ORCA based local avoidance for crowds.
1. Installation and requirements
- Unity 2021.3 LTS or newer (tested with Unity 6).
- No external dependencies. Works with Built-in, URP and HDRP.
- Import the package. Everything lives under
Assets/PathFinder. - Optional:
Tools > PathFinder > Create Demo Scenesgenerates five sample scenes intoSamples/Scenes. The scenes are generated procedurally so they never contain pipeline specific materials.
The package is split into assembly definitions: PathFinder.Runtime, PathFinder.Editor, PathFinder.Samples
and PathFinder.Tests.EditMode. Reference PathFinder.Runtime from your own asmdef if you use them.
2. Core concepts
Graph — a set of nodes and connections that describes where agents can walk. A scene can have up to 32 graphs.
Node — one walkable location (a grid cell, a triangle or a waypoint). Nodes have a position, a walkable flag, a penalty (extra cost) and a tag (0..31).
Area — a connected component. After every scan and graph update PathFinder flood fills the graphs and stores an area id on each node. Two nodes with the same area are guaranteed to be reachable from each other; this is used to answer "is a path possible?" instantly and to make unreachable targets cheap to handle.
Path — a request from A to B. Paths are calculated on worker threads and returned on the main thread through a
callback. The result is a list of nodes and a list of world space points (VectorPath).
Seeker — the component that requests paths for one agent and applies modifiers.
Modifier — a component that post-processes the point list (funnel, raycast simplification, smoothing).
Graph update — a runtime change to nodes inside a bounding box: walkability, penalty, tag or a physics rescan.
3. The Pathfinder Manager
Create it with GameObject > PathFinder > Pathfinder Manager. There must be exactly one in the scene.
Inspector sections:
- Graphs — the list of graphs. Use Add Graph... to add one, the Scan button to scan a single graph and Scan All Graphs to scan everything. Graph settings are saved in the scene; node data is rebuilt when scanning.
- Scanning — Scan On Awake scans automatically when the scene starts.
- Threading — Thread Count: -1 = automatic (processor count - 1, max 8), 0 = calculate on the main thread within Max Frame Time Ms per frame, or an explicit number.
- Search — Heuristic (Euclidean is the safe default; None turns A into Dijkstra), Heuristic Scale (values above 1 give faster but slightly less optimal paths), Max Searched Nodes* (0 = unlimited).
- Graph updates — Batch Graph Updates collects updates and applies them at most every Batching Interval seconds. Enable when many updates are issued per second.
- Tags — optional names for the 32 tags, shown in tag fields.
- Debug — gizmo settings: colour mode (Solid / Areas / Penalty / Tags), draw distance culling, surfaces, connections, bounds. Large grids can be expensive to draw; lower the draw distance or disable surfaces.
Runtime API highlights (PathfinderManager.Active):
manager.Scan(); // rescan everything (blocks, pauses threads)
manager.ScanGraph(graph); // rescan one graph
manager.StartPath(path); // queue a path
manager.GetNearest(position, NNConstraint.Default);
manager.UpdateGraphs(new GraphUpdateObject(bounds));
manager.FlushGraphUpdates(); // apply queued updates now
manager.OnGraphsScanned += () => { ... };
manager.OnGraphsUpdated += () => { ... };
4. Graph types
Grid Graph
A regular grid of square nodes. Best for open terrain, RTS/tower defence maps and anything that changes at runtime.
- Shape — Width and Depth in nodes, Node Size in world units, Center, Rotation (rotate 90 degrees around X for 2D XY games). The scene view shows the outline and a move handle. Fit to object sizes the grid to the bounds of an object.
- Connections — 4 or 8 neighbours, Cut Corners (allow diagonals past obstacle corners), Max Climb (max height difference between neighbours, 0 = unlimited), Max Slope in degrees.
- Erosion — makes nodes next to obstacles unwalkable N times so agents keep a distance from walls. With Erode Using Tags the nodes are tagged instead (tag = Erosion Tag + iteration) so different agents can decide whether to use them.
- Height testing — casts a ray (or sphere with Thickness) from Ray Length above the grid plane downwards to place each node on the ground. Unwalkable When No Ground removes nodes over holes.
- Collision testing — tests a capsule, sphere or ray at every node against Mask. Size it like your agent.
- Penalties — optional penalties by slope and by height.
Extra features: Linecast(from, to, out hit) walks the cells between two points and reports the first blocked
boundary. Graph updates support physics rescans (UpdatePhysics = true), used by DynamicObstacle.
Layered Grid Graph
A grid graph where every cell column can hold several nodes (floors of a building, bridges).
Extra settings: Max Layers, Character Height (minimum head room; nodes with a ceiling closer than this are
unwalkable) and Merge Distance. Everything else works like the grid graph, including updates and linecasts.
Each cell column is scanned with a RaycastAll, so layered grids scan slower than plain grids; keep them as
small as the level allows.
Point Graph
Hand placed waypoints. Assign a Root transform whose children (recursively) become nodes, or a Search Tag.
Nodes within Max Distance are connected, optionally only when a Raycast (with Thickness) finds no obstacle.
From code you can AddNode, Connect and Disconnect at runtime. Nearest node queries are brute force, which is
fine for a few thousand nodes.
NavMesh Graph
A graph of triangles. Two sources:
- Mesh Asset — any mesh (modelled or generated). Offset, Rotation and Scale place it in the world.
- Unity NavMesh — the NavMesh baked with Unity's navigation tools (Window > AI > Navigation or the AI Navigation package). Bake as usual, then scan. This gives you voxel based NavMesh generation for free while all pathfinding, tags, penalties, modifiers and local avoidance are handled by PathFinder.
Vertices closer than Weld Threshold are merged so adjacent triangles become neighbours. Nearest node queries use a bucket grid (Lookup Cell Size, 0 = automatic). The graph supports linecasts (walking across triangle edges). Always add a Funnel Modifier to seekers using navmesh graphs; the raw path goes through triangle centres.
You can also build a navmesh graph from code with graph.Build(vertices, triangles) followed by
manager.RebuildNodeLookup() and manager.RecalculateAreas() under the write lock, or simply manager.ScanGraph(graph)
after assigning SourceMesh.
Recast Graph (automatic navmesh)
Generates a navmesh from the scene automatically. Set Bounds Center / Bounds Size (scene handles are available), pick what to voxelize (Rasterize Colliders, Meshes, Terrains), a layer Mask and optionally an Exclude Tag for your agents, then scan.
Recast settings:
- Cell Size / Cell Height — voxel resolution. 0.25 to 0.5 horizontally is typical. Smaller = more detail, slower.
- Agent Height, Agent Radius, Max Climb, Max Slope — describe the character. The mesh is shrunk by the radius so agents never clip walls; steps up to Max Climb (stairs) are walkable; low ceilings block.
- Max Edge Error — how closely the simplified border follows the voxels.
- Min Region Area — removes tiny islands (tops of beams, ledges).
- Max Edge Length — long outer edges are split so the triangulation (which is also Delaunay-flipped) has well shaped triangles instead of slivers. Lower values give a denser, more regular mesh.
The pipeline is: rasterize triangles into a heightfield, filter ledges and low ceilings, build a compact heightfield, erode by the agent radius, partition into regions, trace and simplify contours, triangulate and weld. The result is a normal navmesh graph, so everything from the NavMesh Graph section applies (use a Funnel Modifier). Build times: a 60 x 60 m level at 0.3 m cells takes a few tens of milliseconds.
Give agents no colliders, or put them on a layer excluded from Mask / give them the Exclude Tag, otherwise they are baked into the mesh.
5. Requesting paths from code
The simplest way is through a Seeker:
using PathFinder;
public class Example : MonoBehaviour
{
Seeker seeker;
void Start()
{
seeker = GetComponent<Seeker>();
seeker.StartPath(transform.position, target.position, OnPathComplete);
}
void OnPathComplete(Path path)
{
if (path.Error) { Debug.Log(path.ErrorLog); return; }
// path.VectorPath is a List<Vector3> of waypoints, path.Nodes the nodes
Debug.Log("Path with " + path.VectorPath.Count + " points, state " + path.CompleteState);
}
}
Without a Seeker (no modifiers are applied):
var path = ABPath.Construct(start, end, p => Debug.Log(p.CompleteState));
PathfinderManager.Active.StartPath(path);
Path types:
ABPath— from A to B.MultiTargetPath— from A to the cheapest of several targets (ChosenTargetIndextells which one).FleePath— moves away from a point;SearchLengthis the cost budget,AimStrengthhow strongly to prefer distance from the threat.
Path settings (all optional): TraversableTags, TagPenalties, NNConstraint (which graphs / tags / area may be
used for the start and end node, XZ distance, max distance), HeuristicOverride, CalculatePartial,
MaxSearchedNodesOverride, StartSnapping / EndSnapping.
CompleteState is Complete, Partial (target unreachable; the path leads to the closest reachable node) or
Error (see ErrorLog). SearchedNodes and DurationMs are filled for profiling.
In edit mode (no worker threads) StartPath calculates synchronously, which is handy for editor tools and tests.
manager.CalculateImmediately(path) does the same at runtime when you need a result right now.
6. Seeker and modifiers
Seeker settings: Traversable Tags (bit mask), Tag Penalties, Graph Mask, start/end snapping, Allow
Partial Paths, gizmo colour. Requesting a new path cancels the previous pending one. Subscribe to
seeker.PathCallback to receive every path, or pass a callback to StartPath.
Modifiers live on the same GameObject and run in ascending Order:
- Funnel Modifier (order 10) — string pulling through the portals between consecutive nodes. Gives the shortest path inside the corridor of nodes. Required for navmesh graphs, useful on grids. Portal Shrink keeps the path that far from portal ends (set it to the agent radius so corners are not clipped); Split Grid Diagonals turns diagonal grid steps into two straight steps so portals are full cell edges instead of single corner points.
- Raycast Modifier (order 20) — removes waypoints that can be skipped in a straight line. Use Graph Raycasting uses the graph's own linecast (exact); Agent Radius adds two parallel linecasts so shortcuts keep their distance from corners. Use Physics Raycasting uses scene colliders with an optional thickness. Max Lookahead bounds the cost on long paths. Off-mesh link points are never removed.
- Simple Smooth Modifier (order 30) — Simple (subdivide + average), Corner Cutting (Chaikin) or Bezier. Smoothing can move the path slightly off the walkable surface; keep the strength low or use erosion.
Write your own by deriving from PathModifier and implementing Apply(Path path).
7. Moving agents (AIPath)
Add AIPath (it requires a Seeker). Set Destination from code or add AIDestinationSetter with a target
transform. The agent repaths every Repath Rate seconds and follows the path.
Movement settings: Max Speed, Max Acceleration, Rotation Speed, Slowdown Distance, Pick Next Waypoint Distance, End Reached Distance. Mode is Auto (CharacterController or Rigidbody when present, otherwise the transform), and gravity is applied in CharacterController mode. In Transform mode the agent follows the path height, so it walks up ramps on layered grids without physics.
Off-mesh links: when a path crosses a Node Link the agent switches to Link Traversal mode: Jump (parabolic arc
with Jump Height), Straight or Teleport, at Link Speed Multiplier times the max speed. Local avoidance
and gravity are suspended while crossing; IsTraversingLink is true and OnLinkStarted / OnLinkFinished fire
with the link segment, which is where you trigger a jump animation.
Useful members: ReachedEndOfPath, ReachedDestination, RemainingDistance, Velocity, IsStopped,
CanMove, CanSearch, SearchPath(), SetPath(path), Teleport(position), events OnTargetReached and
OnPathCalculated. AIPath.All lists every enabled agent.
Patrol cycles an agent through a list of transforms with an optional delay, sequentially or randomly.
8. Local avoidance (RVO)
Add GameObject > PathFinder > RVO Simulator once per scene and an RVOController to each agent. AIPath
detects the controller and routes its desired velocity through the simulation automatically. Objects without
AIPath can set DesiredVelocity themselves and read CalculatedVelocity, or tick Move Self.
The simulation is an original implementation of ORCA (optimal reciprocal collision avoidance): every neighbour contributes a half-plane of allowed velocities and a small linear program finds the allowed velocity closest to the desired one. Settings: simulation FPS, Agent Time Horizon (how early agents react to each other), Obstacle Time Horizon, Max Neighbours, Neighbour Distance, Symmetry Breaking and multithreading.
Per agent: Radius, Height (agents on different floors ignore each other), Priority (higher priority agents are avoided more by others), Locked (does not move but is avoided), RVO Layer and Collides With masks.
RVOObstacle adds static obstacles: a box from the transform (or BoxCollider) or a custom polyline. Tick Dynamic for moving obstacles. Obstacles are handled by treating the closest point on each edge as a static agent, which is robust for walls and boxes but does not model long concave shapes perfectly.
9. Tags and penalties
Every node has a tag (0..31) and a penalty in world units (a penalty of 5 costs the same as walking five extra units). Seekers choose which tags they may traverse (Traversable Tags) and how expensive each tag is (Tag Penalties). Typical uses: "road" tag with negative penalty preference for vehicles, "water" only for amphibious units, "door" tag that some factions cannot pass.
Set tags and penalties with graph updates, with GraphUpdateScene components placed in the level, with erosion
tags, or from code by iterating graph.GetNodes(...) under manager.GraphLock write lock.
10. Graph updates at runtime
var guo = new GraphUpdateObject(collider.bounds)
{
UpdatePhysics = true, // rescan height and collision for the nodes (grid graphs)
ModifyWalkability = false, // or set SetWalkability
AddPenalty = 10f,
ModifyTag = true, SetTag = 2
};
PathfinderManager.Active.UpdateGraphs(guo);
Updates are queued and applied on the main thread during the next Update (or the next batch flush) while
pathfinding threads are paused. Areas are recomputed afterwards. NodeFilter and CustomAction let you apply
arbitrary changes.
Components:
- GraphUpdateScene — applies an update from the bounds of the object (collider, renderer or box size) on start and after every rescan. Great for mud, roads, forbidden zones.
- DynamicObstacle — watches a collider and issues physics rescans whenever it moves. Use it on doors, crates
and vehicles. Combine with
RVOObstacleso agents also steer around it locally. - NodeLink — an off-mesh link. Connects the node nearest to the object with the node nearest to End (any
graph, so it can bridge two graphs). One Way, Cost Factor (below 1 = attractive shortcut), Max Node
Distance and an optional tag for both ends. Links are re-applied after every scan. The path simply passes
through the link; react to
AIPath.OnPathCalculatedor checkpath.Nodesforlink.StartNode/link.EndNodeif you want to play a jump animation. From code:link.Apply()/link.Remove(), or usenode.AddExtraConnection(other, cost)directly under the manager's write lock.
Graph cache
Scanning needs physics queries and can take a while on big levels. Press Save Cache To File... on the manager to
store the node data of all graphs in a .bytes asset, assign it to Cache File and tick Load Cache On Awake.
At startup the nodes are restored in a few milliseconds without touching physics. The cache stores nodes only; the
graph settings stay in the scene, and the graph list must match the one used when saving (same count and types),
otherwise loading fails and the manager falls back to scanning. Grid, layered grid, point, navmesh and recast graphs
support caching. From code: manager.SaveCache() returns the bytes, manager.LoadCache(bytes) restores them.
Remember to save the cache again after changing the level.
10b. 2D games (XY plane)
Set Movement Plane on the manager to XY. Then:
- Grid graph: set Rotation to (-90, 0, 0) so the grid lies in the XY plane, tick Use 2D Physics (collision testing uses Physics2D overlap tests, the height test is skipped) and size the collision diameter like your sprite.
- AIPath: movement stays in XY, Rotation 2D chooses how the sprite turns (up or right towards the velocity, or none). Rigidbody2D is supported (kinematic via MovePosition, dynamic via velocity).
- Local avoidance: the RVO simulator copies the plane from the manager; RVOObstacle works with BoxCollider2D.
- Modifiers, funnel, click handling in the samples and
PathUtilities.GetPointsAroundPointare plane aware.
The 07 2D Grid Graph demo scene shows a complete 2D setup with sprites and 2D colliders.
11. Utilities
PathUtilities.IsPathPossible(a, b) (nodes or positions), GetReachableNodes(seed, tagMask, maxDepth),
GetNodesWithinCost(seed, maxCost), GetPointsAroundPoint(center, count, spacing) for group formations,
GetRandomNode(list).
manager.GetNearest(position, constraint) returns the closest node and the position clamped to it.
NNConstraint lets you restrict graphs, walkability, tags, area and distance.
12. Performance guide
- Grid graph cost scales with node count. 200 x 200 = 40k nodes is small; 1000 x 1000 = 1M nodes is fine for searching but slow to scan and draw. Increase Node Size before increasing the count.
- Use erosion or a larger collision diameter instead of smoothing to keep agents away from walls.
- Heuristic Scale 1.2 to 2 greatly reduces searched nodes on large open maps at a small optimality cost.
- Keep Repath Rate at 0.3 to 1 second for most games; only repath faster for a few important agents.
- Large numbers of graph updates: enable Batch Graph Updates.
- Gizmos: reduce Draw Distance, disable Show Surface or tick Only When Selected for big graphs. The grid graph stops drawing nodes above Max Gizmo Nodes.
- Local avoidance: lower Max Neighbours and Neighbour Distance for very large crowds. Multithreading kicks in automatically above 32 agents.
- Paths are calculated on worker threads, so calculating many paths per frame is cheap for the main thread; the callbacks and modifiers run on the main thread.
13. Troubleshooting
- "No PathfinderManager in the scene" — add one from the GameObject menu.
- "No graphs have been scanned" — enable Scan On Awake or call
manager.Scan(). - All nodes are unwalkable — check the collision mask (the ground itself must not count as an obstacle: put it on a layer excluded from Collision Mask, or raise Height Offset), and the height test mask.
- Agents walk through walls — the collision diameter is smaller than the agent, or the walls have no colliders.
- Small isolated areas on top of walls — the height test also hits the tops of obstacles and creates walkable nodes there. Put obstacles on their own layer and exclude that layer from the Height Test Mask (keep it in the Collision Mask). The demo scenes use the built-in "Ignore Raycast" layer for this.
- Paths hug corners — add erosion or increase the collision diameter.
- Navmesh paths zig-zag — add a Funnel Modifier.
- Navmesh triangles are not connected — increase Weld Threshold.
- Layered grid misses a floor — increase Max Layers or Ray Length; check Character Height.
- RVO agents jitter in dense crowds — lower the simulation FPS to 20, increase the time horizon slightly, or give important agents a higher priority.
13b. Tests and demo captures
Tests/EditMode contains unit tests for the core (heap, grid, navmesh, funnel, tags, cache, node links, recast
builder, ORCA). Tests/PlayMode runs the generated demo scenes for real: agents are sent to targets and the tests
assert they arrive, climb the ramp, cross the RVO circle and that dynamic obstacles update the grid. Run them in
Window > General > Test Runner or from the command line:
Unity.exe -batchmode -projectPath <project> -runTests -testPlatform PlayMode -testCategory Agents
The Marketing category records PNG frame sequences of scripted scenarios into <project>/Marketing/frames
(rendered from the scene camera at 1280 x 720, 30 fps). Encode them with ffmpeg using
Marketing/encode_videos.py in the project root (creates one MP4 per scene, a combined showreel and a GIF preview).
14. API overview
Namespace PathFinder
PathfinderManager— graphs, scanning, path queue, graph updates, nearest node queries, events.NavGraph,GraphNode,Connection,NNInfo,NNConstraint,GraphMask,GraphHitInfo,Heuristic.Path,ABPath,MultiTargetPath,FleePath,PathCompleteState,EndpointSnapping.GraphUpdateObject,GraphUpdateScene,DynamicObstacle,NodeLink,GraphCache.Seeker,AIPath,AIDestinationSetter,Patrol.MovementPlane,PlaneUtil,PathUtilities,BinaryHeap,PathfindingContext,GizmoSettings,TagMaskAttribute,TagFieldAttribute.
Namespace PathFinder.Graphs
GridGraph,GridNode,LayeredGridGraph,PointGraph,PointNode,NavMeshGraph,TriangleNode.
Namespace PathFinder.Graphs.Recast
RecastGraph,RecastSettings,RecastBuilder(static, usable with your own triangle lists),PrimitiveGeometry.
Namespace PathFinder.Modifiers
PathModifier,FunnelModifier,RaycastModifier,SimpleSmoothModifier.
Namespace PathFinder.RVO
RVOSimulator,RVOController,RVOObstacle,RVOAgent,RVOSegment,ORCA.
Namespace PathFinder.Editor
PathfinderManagerEditor,GraphEditor(+CustomGraphEditorAttribute),DemoSceneBuilder,PackageExporter.
Writing a custom graph
Derive from NavGraph, add [Serializable] and [GraphType("My Graph")], create nodes deriving from GraphNode
(implement GetConnections and GetPortal), implement Scan, GetNearest, GetNodes and NodeCount.
Optionally override UpdateArea, Linecast, GetBounds and OnDrawGizmos. The graph appears in the
Add Graph... menu automatically. Add a GraphEditor with [CustomGraphEditor(typeof(MyGraph))] for custom
inspector or scene handles.