Recursive AI

Getting started with OnePath

All onepath docs

Install OnePath for .NET 10, find a path on a grid, build a navigation mesh from level geometry and query it, and walk an agent across it in a crowd, with results that are the same bits on every platform.

Install

OnePath targets net10.0, so you need the .NET 10 SDK. This guide uses 1.1.0.

Terminal
dotnet new console -o OnePathStart
cd OnePathStart
dotnet add package RecursiveAI.OnePath --version 1.1.0

Its only runtime dependency is OneMath (1.0 or later), installed with it, for vectors and deterministic math. OnePath works under NativeAOT, trimming and browser WebAssembly, and never reads files or the network: glTF files, saved meshes and snapshots come in as bytes you supply.

One using RecursiveAI.OnePath; reaches every type on this page; the navmesh calls also use OneMath’s vectors.

A first program

C#
using RecursiveAI.OneMath;
using RecursiveAI.OnePath;
 
// 1. A square grid: '.' open, '#' wall.
var grid = Grid.FromText("""
    ........
    .#####..
    .#...#..
    .#.#.#..
    ...#....
    """);
GridPath path = grid.FindPath(new Cell(0, 0), new Cell(4, 3));
Console.WriteLine($"grid: found {path.Found}, cost {path.Cost:F4}, {path.Cells.Length} cells");
Console.WriteLine("  " + string.Join(" ", path.Cells.ToArray().Select(c => $"({c.X},{c.Y})")));
 
// 2. A navigation mesh from level geometry: a 40 x 40 floor, Y up.
var floor = new[]
{
    new Triangle3D(new Vector3D(0, 0, 0), new Vector3D(0, 0, 40), new Vector3D(40, 0, 0)),
    new Triangle3D(new Vector3D(40, 0, 0), new Vector3D(0, 0, 40), new Vector3D(40, 0, 40)),
};
NavMesh level = NavMesh.Build(floor, NavSettings.Humanoid);
PathResult route = level.FindPath(new Vector3D(3, 0, 3), new Vector3D(36, 0, 36));
Console.WriteLine($"navmesh: has path {route.HasPath}, length {route.Length:F4}, {route.Points.Count} points");
 
// 3. A crowd on that mesh, stepped with a fixed time step.
Crowd crowd = level.CreateCrowd();
Agent walker = crowd.Add(new Vector3D(3, 0, 3), Agent.Humanoid);
walker.SetDestination(new Vector3D(36, 0, 36));
for (int i = 0; i < 20; i++) crowd.Step(0.05);
Console.WriteLine($"crowd: after 1 s at {walker.Position}, {walker.RemainingDistance:F4} m to go");
Text
grid: found True, cost 11.0000, 12 cells
  (0,0) (0,1) (0,2) (0,3) (0,4) (1,4) (2,4) (2,3) (2,2) (3,2) (4,2) (4,3)
navmesh: has path True, length 46.6690, 2 points
crowd: after 1 s at (5.05112451814824, 0, 4.929277245053733), 43.8543 m to go

What each part does

  • Grid.FromText reads . as open and # as a wall; digits 1–9 are area ids that you give a cost with grid.Areas[id] = 3.0. Moves are eight-connected without cutting corners by default, so the path takes no diagonal step past the corner of a wall. GridOptions picks the algorithm (A*, JPS, JPS+, Theta*, Lazy Theta*, HPA*), agent size, extra costs and blocked cells: see Grid pathfinding.
  • NavMesh.Build turns a triangle soup (Y up) into a tiled navigation mesh for an agent described by NavSettings (radius, height, step and slope). NavSettings.Humanoid is a preset. NavMesh.Build2D builds one from a tile map or outlines, and NavMesh.BuildGltf reads a glTF file.
  • FindPath returns a PathResult with HasPath, the string-pulled Points, Length and the polygon corridor. On an open floor that is two points, the start and the goal.
  • Crowd moves agents along their corridors and keeps them apart with ORCA. You call Step with a fixed time step; the crowd has no clock of its own.

World positions are double and exact within ±2^21; a coordinate beyond that throws ArgumentOutOfRangeException.

Determinism

Results depend only on the inputs and options: never on the OS, CPU, SIMD width, runtime, JIT tier, WebAssembly or thread count. Ties break on node or polygon index, never on hash order. No 1.x release changes an existing path, mesh build, query, search or crowd step, and every 1.x release reads every format an earlier 1.x release saved. That makes OnePath safe for lockstep and rollback hosts: see Crowds in a rollback game.

Next