Skip to content

Path Request API

Overview

The Path Requests API provides multiple methods for requesting pathfinding operations, from simple synchronous calls to advanced asynchronous job management.

Simple Path Request

--> GetPath() will immediately return a path and is the easiest way but is synchronous:

var pathConfig = new PathConfig()
{
    CollapseSkips = true,
    UseClosestTarget = false,
    QueryDynamic = false
};

// Generate immediately:
List<Vector3> curPath = grid.GetPath(transform.position, target.position, pathConfig);

Recommended Workflow

--> Queuing paths is the most reliable (threaded) but takes a bit more maneuvering:

List<Vector3> curPath = null;
var pathRequest = new PathRequest(transform.position, target.position, pathConfig, result =>
{
    curPath = result.Path;
});

grid.RequestPathQueued(pathRequest); // The callback will be executed when the job is complete


Configuration

Before jumping into the API, it's important to know the extra path configuration options. We'll discuss "Closest Target" here and "Collapse Skips" here. "Query Dynamic" is covered in Dynamic Obstacles.

PathConfig

Configuration options for path generation.

public struct PathConfig
{
    public bool CollapseSkips;      // Expand jump points into full paths
    public bool QueryDynamic;       // Check dynamic obstacles
    public bool UseClosestTarget;   // Find closest reachable tile if target blocked
}
Option Default Description
CollapseSkips true Expand JPS jump points into individual tiles for smooth movement
QueryDynamic true Include dynamic obstacles in pathfinding
UseClosestTarget true If target is blocked, pathfind to nearest walkable tile

Closest Target

This configuration parameter will ensure that when pathfinding to a target, if it is blocked or not reachable a path is still returned pathing to the most promising tile (by f-score). This is especially helpful when using Dynamic Obstacles, or when the target may be blocked but we still want to get an approximate path to near the target.

Blocked Start/Target

When "closest target" is not used, paths are STRICT. If the start position is blocked by an obstacle on the static collision matrix OR the target position is blocked by an obstacle on the static or dynamic collision matrix, the path returned will be empty.

Collapse Skips

For many systems, paths need to be contiguous blocks, but jump point algorithms like JPS4 by nature skip nodes in the path during generation. This configuration parameter will ensure after a job completes, the resulting path is converted to contiguous connected tiles and jump skips are collapsed.

Collapse Skips

  • True: Path includes every tile (required for grid-based movement)
  • False: Path only includes jump points (for visualization/debugging)
  • Only affects JPS algorithms (A* always returns full paths)

Path Requests

PathRequest

A path request wrapper with configuration and callback. OnComplete is called when a pathing job is completed regardless of its result / cancellation.

public class PathRequest
{
    public Vector3 Start;
    public Vector3 Target;
    public Action<PathResult> OnComplete;
    public PathConfig Config;
}
public PathRequest(
    Vector3 start, 
    Vector3 target, 
    Action<PathResult> onComplete,
    bool collapseSkips = true,
    bool queryDynamic = true,
    bool useClosestTarget = true
)
public PathRequest(
    Vector3 start,
    Vector3 target,
    PathConfig config,
    Action<PathResult> onComplete
)

PathResult

The result of a path request, including an output path and a record of the Config used to generate it. Status is important if the grid changes while a path is queued and a job needs to be re-queued.

public struct PathResult
{
    public EPathJobStatus Status;  // Success/failure status
    public List<Vector3> Path;     // Resulting world-space path
    public PathConfig Config;      // Configuration used
}

Path Job Status

public enum EPathJobStatus
{
    Success,              // Path found successfully
    Cancelled_Rebuild,    // Grid was rebuilt during pathfinding
    Cancelled_Lifetime,   // Grid was destroyed/disabled
    Failed                // No path found or error occurred
}

GetPath()

Get a path immediately (synchronous), blocking until completion.

This is great for quick, single use path finding, if the grid is small, or if there aren't many agents and you are yielding in between.

public List<Vector3> GetPath(
    Vector3 start, 
    Vector3 target, 
    PathConfig config
)

Parameters:

  • start: Start position in world space
  • target: Target position in world space
  • config: Path configuration options

Returns: List<Vector3> containing the path in world space (empty if no path found)

Example: Simple Path Request

var pathConfig = new PathConfig()
{
    CollapseSkips = true,
    UseClosestTarget = false,
    QueryDynamic = false
};

// Generate immediately:
List<Vector3> curPath = grid.GetPath(transform.position, target.position, pathConfig);

GetPathAsync()

Get a path asynchronously using a coroutine.

If you are using Awaitable or a library like Cysharp.UniTask you can convert coroutines to any needed Unity "async" operations with the System.Task conventions.

public IEnumerator GetPathAsync(PathRequest request)

Parameters:

  • request: This is a PathRequest containing start, target, config, and a completion callback.

Example: Coroutine Path Request

List<Vector3> curPath = null;
var pathConfig = new PathConfig()
{
    CollapseSkips = true,
    UseClosestTarget = false,
    QueryDynamic = false
};

var pathRequest = new PathRequest(transform.position, target.position, pathConfig, result =>
{
    curPath = result.Path;
});

var handle = StartCoroutine(grid.GetPathAsync(pathRequest));

Job Queue

The easiest way to queue and wait for multiple jobs without blocking the main thread or yielding frames is using the GridBuilder's Job Queue system.

This is using Burst Job system to complete multi-threaded operations using the maxConcurrentJobs field on the GridBuilder object. Tune this depending on the size of your grid, number of agents, and target platform. See Grid Builder Configuration for more.

Automatic Processing

The queue automatically schedules new jobs up to maxConcurrentJobs and completes callbacks on the main thread.

RequestPathQueued

Add a path request to the managed job queue for automatic processing.

public void RequestPathQueued(PathRequest request)

Parameters:

  • request: This is a PathRequest that will be queued and processed automatically

Example: Queued Path Requests

List<Vector3> curPath = null;
var pathConfig = new PathConfig()
{
    CollapseSkips = true,
    UseClosestTarget = false,
    QueryDynamic = false
};

var pathRequest = new PathRequest(transform.position, target.position, pathConfig, result =>
{
    curPath = result.Path;
});

grid.RequestPathQueued(pathRequest); // The callback will be executed when the job is complete

Queue Status

public int maxConcurrentJobs = 8;  // Inspector configurable

The queue automatically manages jobs by:

  1. Scheduling new jobs when slots are available
  2. Checking for completed jobs every frame
  3. Invoking callbacks on the main thread
  4. Marking requests dirty if the grid is re-built while executing

WaitForAllJobs()

Wait until all queued and active jobs complete.

public IEnumerator WaitForAllJobs()

Waiting for Batch Completion

foreach (var agent in agents)
{
    PathRequest request = agent.GetPathRequest(); // Here "agent" handles the callbacks on completion
    gridBuilder.RequestPathQueued(request);
}

// Wait for all to finish
yield return gridBuilder.WaitForAllJobs();

WaitForAllJobs

Calling WaitForAllJobs can be dangerous if you have more than one object queuing jobs at once, since processing jobs can take multiple frames. Alternates are counting remaining jobs on your own semaphore-like approach (remaining-- within the callback), or using the RequestPath() JobHandle approach manually and batching Jobs in a group.


Job Cancellation

Jobs are automatically cancelled when:

  • Grid is rebuilt via Build() → Status: Cancelled_Rebuild
  • Grid is destroyed or disabled → Status: Cancelled_Lifetime

If a job is running and static collision is re-built, it will be "invalidated." The callback is still executed but the result is PathResult.EPathJobStatus.Cancelled_Rebuild. In this case the resulting path is null.

Manual cancellation:

// Cancel all pending jobs (not started yet)
private void CancelPendingJobs(PathResult.EPathJobStatus reason)

// Cancel all active jobs (currently running)
public void CancelActiveJobs(PathResult.EPathJobStatus reason)

Active Job Cancellation

CancelActiveJobs() forces completion on the main thread and should be avoided when possible. Let jobs finish naturally when possible.


Advanced Usage

Grid-Space Pathfinding

For working directly with grid coordinates:

public bool TryGetGridPath(
    ref NativeList<int2> pathResult,
    int2 gridStart,
    int2 gridTarget,
    PathConfig config
)

RequestPath()

Get direct access to the Unity Job System and use the internal scheduling without the queue system.

public PathHandle RequestPath(
    int2 start, 
    int2 target, 
    PathConfig config, 
    Allocator allocator = Allocator.TempJob
)

Parameters:

  • start: Start position in grid space
  • target: Target position in grid space
  • config: Path configuration
  • allocator: Memory allocator for the job (default: TempJob)

Returns: PathHandle with job handle and result arrays

PathHandle

Internal wrapper with a JobHandle that tracks a pathfinding job request.

public struct PathHandle : IDisposable
{
    public JobHandle Handle;      // Handle for scheduled pathfinding job.
    public NativeList<int2> Path; // Output Path of grid points (this may not be collapsed for algorithms w/ skip nodes)
    public NativeList<JPSDebugStep> DebugSteps; // Output debug info on completion
    public bool IsCompleted; // Status of the job
    public void Complete();  // Immediately complete the JobHandle (synchronous) 
}