Spatial and games

Tracer: pathfinding and game AI for .NET

Pathfinding is the easy part. Tracer does the rest.

  • Release 2.0.2
  • Triangle navmesh and a bake-free tile lane
  • Self-tuning concurrency
  • net8.0 and net10.0
dotnet add package EvaluatedApplications.Tracer

Commercial licence for commercial use. Evaluation and non-commercial use are permitted.Licence terms

The field

A baked level, fourteen agents and the paths Tracer returned. Switch the view to close a doorway, compare single queries with the swarm tick, or flood a tile range. Every line is package output.

Plan view of the level with the swarm paths A 32 by 16 level with two walls, each with two doorways. 14 agents start in the left room and Tracer returns a path for each toward the goals in the right rooms.
Data behind the diagram
Totals by view, from 14 agents on a level baked to 788 triangles
ViewPaths foundMean waypointsTotal length (cells)Agents re-routedDeepest corner cut (cells)
Swarm tick14 of 1410.5343.6none0.50
Doorway closed14 of 1412.7373.612 of 14
Single queries14 of 146.7339.5none0.11
Per agent: start, goal and the path Tracer returned in each view
AgentStartGoalSwarm waypointsSwarm lengthClosed waypointsClosed lengthRe-routedSingle waypointsSingle length
Agent 1(1.5, 1.5)(28.5, 8.5)929.41332.5yes729.4
Agent 2(3.5, 2.5)(28.5, 8.5)927.01330.1yes727.0
Agent 3(5.5, 1.5)(28.5, 8.5)925.91629.8yes725.4
Agent 4(7.5, 3.5)(28.5, 8.5)923.41627.0yes622.6
Agent 5(2.5, 5.5)(28.5, 8.5)1027.91331.1yes728.1
Agent 6(6.5, 5.5)(28.5, 8.5)1023.71328.0yes624.1
Agent 7(9.5, 6.5)(28.5, 8.5)920.41326.6yes821.2
Agent 8(1.5, 8.5)(28.5, 8.5)1229.81230.0yes828.8
Agent 9(4.5, 9.5)(28.5, 8.5)1226.41226.6yes725.9
Agent 10(7.5, 8.5)(28.5, 8.5)1224.71225.2yes624.0
Agent 11(2.5, 11.5)(28.5, 8.5)1129.41129.4no727.2
Agent 12(5.5, 12.5)(28.5, 8.5)1325.01226.7yes724.9
Agent 13(8.5, 13.5)(28.5, 8.5)1422.71422.6yes722.9
Agent 14(10.5, 8.5)(16.5, 13.5)88.088.0no47.9
Tile lane from tile (4, 8)
MeasureValue
Tiles reachable within 7 steps96
Tiles in line of sight179
Reachable tiles beside a wall14
Generated by running the published EvaluatedApplications.Tracer package (release 2.0.2). Every number is the package's own output.

What Tracer is

Tracer is a pathfinding and game-AI SDK for real-time simulations with many moving agents: crowds, RTS-style unit groups and tactical squads. It bakes triangle navmeshes, routes single agents and whole swarms across them, reacts to obstacles that appear or vanish mid-game, and adds the game-AI toolkit around pathfinding: line of sight, fog of war, influence maps and combat engagement.

  • A swarm costs close to one agent

    Agents that share a goal share one solve, so five hundred agents heading to the same point cost close to one. Adaptive path budgeting keeps large swarms inside a frame-time budget under pressure.

  • Obstacles change without a re-bake

    Block and unblock regions of a baked mesh while the game runs. The mesh handle is immutable, so you swap the new one in between ticks.

  • Everything around the path

    Line of sight, fog of war, influence maps, congestion analysis, steering behaviors and combat resolution ship in the same SDK, on the same pipeline runtime.

Quick start

Bake a small room with a doorway, query a path, run a swarm, then close the doorway.
C#
using System.Numerics;
using Tracer;
using Tracer.Models;

var world = new PathfindingWorld();

// A 6x4 room with a wall down the middle and a doorway in it.
// Two triangles per walkable cell; vertices sit on the integer lattice.
var vertices = new List<Vector2>();
var triangles = new List<(int A, int B, int C)>();
var lattice = new Dictionary<(int, int), int>();
int V(int x, int y)
{
    if (!lattice.TryGetValue((x, y), out var i)) { i = vertices.Count; lattice[(x, y)] = i; vertices.Add(new(x, y)); }
    return i;
}
for (int y = 0; y < 4; y++)
    for (int x = 0; x < 6; x++)
    {
        bool wall = x == 3 && y != 1;           // the doorway is the cell (3, 1)
        if (wall) continue;
        triangles.Add((V(x, y), V(x + 1, y), V(x + 1, y + 1)));
        triangles.Add((V(x, y), V(x + 1, y + 1), V(x, y + 1)));
    }

var mesh = await world.CreateNavMeshBakerService().BakeAsync(vertices, triangles);
Console.WriteLine($"triangles: {mesh.TriangleCount}");

// One smoothed path.
var path = await world.CreateSingleAgentService()
    .QueryPathAsync(mesh, new Vector2(0.5f, 3.5f), new Vector2(5.5f, 3.5f));
Console.WriteLine($"single path: {path.Count} waypoints, ends at {path[^1]}");

// A swarm sharing one goal is solved once.
var goal = new Vector2(5.5f, 0.5f);
var agents = Enumerable.Range(1, 3)
    .Select(i => new AgentDto(Id: i, Position: new Vector2(0.5f, i - 0.5f), Goal: goal, GoalChanged: true))
    .ToList();
var tick = await world.CreateMultiAgentService().TickAsync(agents, mesh, tickNumber: 0);
Console.WriteLine($"swarm: {tick.Paths.Count(p => p.PathFound)} of {agents.Count} agents have a path");

// Close the doorway at runtime. No re-bake.
var blocked = await world.CreateDynamicObstacleService()
    .UpdateAsync(mesh, new[] { new NavMeshBlockedZone(Center: new Vector2(3.5f, 1.5f), Radius: 0.6f) });
var after = await world.CreateSingleAgentService("after")
    .QueryPathAsync(blocked, new Vector2(0.5f, 3.5f), new Vector2(5.5f, 3.5f));
Console.WriteLine($"doorway closed: path found = {after.Count > 0}");
Output
triangles: 42
single path: 4 waypoints, ends at <5.5, 3.5>
swarm: 3 of 3 agents have a path
doorway closed: path found = False

This is the complete program, compiled and run against the published package.

Capabilities

  • Navmesh baking

    Turn triangle geometry into a queryable navmesh, with obstacle-polygon exclusion and an optional hierarchical bake for large levels, or layered meshes for ground, air and water.

  • Single and multi-agent paths

    One-shot smoothed paths, batches in parallel, or a swarm tick where agents with the same goal reuse one solve.

  • Dynamic obstacles

    Block and unblock circular zones of a baked mesh at runtime without a full bake.

  • Line of sight, fog of war, influence maps

    Visibility and area-control queries for perception and decision-making, with congestion analysis alongside.

  • Combat engagement

    Spatially hashed attacker and defender resolution with pluggable damage, dodge and block formulas.

  • Steering behaviors

    Seek, Wander, Patrol, Flee, Queue and FlowLane, composed through a fluent navigator builder.

  • Grid tactics

    A separate bake-free lane for tile games: line of sight, movement range, cover and target selection over any tilemap.

  • Adaptive budgeting and populations

    Cluster large agent counts and path only representatives when the frame budget is tight, or run several named populations under one shared budget.

Limits

What Tracer does not do, and where to be careful
  • The navmesh is made of triangles, not tiles. A tile game bakes two triangles per walkable cell, or uses the bake-free tile lane.
  • An unreachable or off-mesh goal never throws. A single query returns an empty list, and a swarm result reports that no path was found.
  • Blocking a zone at runtime isolates triangles in place, so the triangle count does not change. Baking with blocked zones excludes them instead.
  • Pressure is a meaningful signal only when a frame-time target is set.
  • Swarm waypoints are shared guidance. On the level in the diagram they cut doorway corners by up to 0.50 of a cell; single-agent queries stay within 0.11 of a cell. Use single queries where exact corner clearance matters.
  • Mesh handles are immutable and safe to read from any thread. Services that persist tuner state should not be driven concurrently under one service key.

Every public type is documented with a worked example in the package readme on NuGet. Open the NuGet page.

Related

Licence

Proprietary. Every package ships as a compiled library. Evaluation and non-commercial development or testing are permitted; commercial, production or revenue-generating use needs a commercial licence from the owner. Read the licence terms.