Searching for paths

Tutorial on how to calculate paths.

This page is relevant if you want to write your own movement script or you have some other reason to calculate paths yourself. If you use one of the built-in movement scripts (e.g AIPath), then you will most likely not have to do any of this. Instead you might be looking for the ai.destination property. Or, if you want to use custom path types with a built-in movement script, use the ai.SetPath method.

If your path requests are failing then you may want to take a look at the page Error messages for a list of common error messages and how to solve them.

Searching for paths using a Seeker

You can search for paths in a number of ways. The easiest method is to have Seeker component attached to the GameObject you want to request paths from and then call Seeker.StartPath(). The Seeker will also automatically handle modifiers.

Note

A Seeker will only process one pathfinding request at a time. If you request a new path before the previous one has been completed, the previous path request will be canceled.

using Pathfinding;

public void Start () {
// Get the seeker component attached to this GameObject
var seeker = GetComponent<Seeker>();

// Start a new path request from the current position to a position 10 units forward.
// When the path has been calculated, it will be returned to the function OnPathComplete unless it was canceled by another path request
seeker.StartPath (transform.position, transform.position+transform.forward*10, OnPathComplete);

// Note that the path is NOT calculated at this stage
// It has just been queued for calculation
}

public void OnPathComplete (Path p) {
// We got our path back
if (p.error) {
// Oh no, a valid path couldn't be found
} else {
// Yay, now we can get a Vector3 representation of the path
// from p.vectorPath
}
}

A common mistake is to assume that the path is already calculated right after the StartPath call. This is however incorrect. The StartPath call will only put the path in a queue. This is done because when many units are calculating their paths at the same time, it is desirable to spread out the path calculations over several frames to avoid FPS drops. We can also calculate the paths in other threads if multithreading has been enabled.

There are, of course, also cases where you need to calculate the path immediately. Then you can use the Path.BlockUntilCalculated method. Path p = seeker.StartPath (transform.position, transform.position + Vector3.forward * 10);
p.BlockUntilCalculated();
// The path is calculated now

You can also wait for the path to be calculated in a coroutine using Path.WaitForPath.

IEnumerator Start () {
var path = seeker.StartPath (transform.position, transform.position+transform.forward*10, OnPathComplete);
// Wait... (may take some time depending on how complex the path is)
// The rest of the game will continue to run while waiting
yield return StartCoroutine (path.WaitForPath());
// The path is calculated now
}

You can also create your own path objects instead of using the Seeker's methods. This will enable you to change settings on the path object before calculating it.

// Create a new path object, the last parameter is a callback function
// but it will be used internally by the seeker, so we will set it to null here
// Paths are created using the static Construct call because then it can use
// pooled paths instead of creating a new path object all the time
// which is a nice way to avoid frequent GC spikes.
var p = ABPath.Construct (transform.position, transform.position+transform.forward*10, null);

// By default, a search for the closest walkable nodes to the start and end nodes will be carried out
// but for example in a turn based game, you might not want it to search for the closest walkable node, but return an error if the target point
// was at an unwalkable node. Setting the NNConstraint to None will disable the nearest walkable node search
p.nnConstraint = NNConstraint.None;

// Start the path by sending it to the Seeker
seeker.StartPath (p, OnPathComplete);

Observant readers may notice the GC allocation incurring every time a delegate to the OnPathComplete delegate is created. It's not much, but it adds up. You can avoid this allocation by caching a delegate in a local field.

protected OnPathDelegate onPathComplete;

void OnEnable () {
onPathComplete = OnPathComplete;
}

void SearchPath () {
// Now use the onPathComplete field, instead of OnPathComplete directly, to avoid a GC allocation
seeker.StartPath (transform.position, transform.position+transform.forward*10, onPathComplete);
}

void OnPathComplete (Path p) {
// Just in case this component was destroyed while a path was being calculated
if (!this) return;
}

The Seeker component is intended to handle pathfinding requests for a single character in the game. For this reason it will only process a single path request at a time. If you call StartPath when another path is already being calculated, it will log a warning saying that the previous path calculation was aborted. If you specifically wanted to cancel the previous path request you can do this without logging a warning by calling Seeker.CancelCurrentPathRequest.

If you want to calculate multiple path simultaneously you should skip the Seeker. Take a look at the Using the AstarPath class directly section instead.

Other types of paths

There are other types of paths than the standard one, for example the MultiTargetPath (Pro feature). These can be started easily as well, especially the MultiTargetPath since the Seeker has a special function for it

// Start a multi target path, where endPoints is a Vector3[] array.
// The pathsForAll parameter specifies if a path to every end point should be searched for
// or if it should only try to find the shortest path to any end point.
seeker.StartMultiTargetPath (transform.position, endPoints, pathsForAll: true, callback: OnPathComplete);

The path will be returned as a Path instance, but it can be casted to for example MultiTargetPath to get all the data. A complete example of MultiTargetPath usage can be found here: MultiTargetPathExample.cs!example.

Note

The MultiTargetPath is an A* Pathfinding Project Pro Feature, so you will get an error if you try the above code using the Free version of the project.

The generic way to start a type of path is simply Path p = MyPathType.Construct (...); // Where MyPathType is for example MultiTargetPath
seeker.StartPath (p, OnPathComplete);

The Construct method is used instead of a consructor so that path pooling can be done more easily.

Using the AstarPath class directly

If you want even more control of each path. Then you can use the AstarPath component directly. The main function you then use is AstarPath.StartPath. This is useful if you want to calculate a lot of paths at the same time. The Seeker is for agents that only have one active path at a time, and if you try to request multiple paths at the same time it will only calculate the last one and cancel the rest.

The Seeker interally uses the AstarPath.StartPath method to calculate the paths.

Note

The paths calculated using AstarPath.StartPath will not be post-processed. However you can call Seeker.PostProcess after a path has been calculated, to post process it using the modifiers attached to a particular Seeker.

// There must be an AstarPath instance in the scene
if (AstarPath.active == null) return;

// We can calculate multiple paths asynchronously
for (int i = 0; i < 10; i++) {
var p = ABPath.Construct(transform.position, transform.position+transform.forward*i*10, OnPathComplete);

// Calculate the path by using the AstarPath component directly
AstarPath.StartPath (p);
}