Optimization
Some tips on how to improve performance.
There are various ways to increase the performance of the system.
But first, profile! Before trying to optimize anything, use a profiler to figure out which part of the code is slowing down the game. Note that if multithreading is used, then pathfinding will only show up on a separate pathfinding thread (you can select this in the Unity profiler).
General tips
Make sure "Show Graphs" (bottom of the A* inspector) is disabled when evaluating performance. For large graphs, the overhead of drawing it every frame can severely slow down the game (this only applies to the editor, not a standalone game).
Optimizing game startup
When the game starts, the AstarPath component will scan all graphs by default. This may take some time depending on your graph settings and graph sizes.
If you have a purely static world, you can cache a scanned graph and just load the cache at startup. Take a look at Saving and Loading Graphs for more info about this.
Alternatively, if you want to show a progress bar while the graphs are being scanned, or just not freeze the game completely, you can scan graphs asynchronously. First, disable A* Inspector → Settings → Scan On Awake. Then, in a custom script, you can scan graphs asynchronously like this:
IEnumerator Start () {
If caching the graph is not an option (perhaps because you have a dynamic level), you may want to tweak your graph settings to make scanning faster, or change the graph type altogether. In general, grid graphs are faster than recast graphs to scan, unless your world is very large. However, pathfinding is typically faster on recast graphs. In the following sections, some tips are included for the different graph types.
foreach (Progress progress in AstarPath.active.ScanAsync()) {
Debug.Log("Scanning... " + progress.ToString());
yield return null;
}
}
Graph Types for more info about the different graph types and their pros and cons.
Optimizing Grid Graph Scanning
There are several ways to reduce the time it takes for a grid graph to be scanned:
Reduce its resolution, if you can.
Disable Height Testing, if you have a completely flat world.
Disable Erosion, as it has a small performance overhead.
Disable Collision Testing, if you do not need it.
Optimizing Recast Graph Scanning
Increase the cell size. This will reduce the resolution at which the graph voxelizes the world.
Use tiling, and use reasonably sized tiles. Values between 64 and 256 voxels are recommended. Tiles can be scanned in parallel, which can give a significant speedup on multicore computers. However, each tile has some overhead, so too small tile sizes will slow down the scan.
Rasterize colliders, instead of meshes. Colliders are typically much simpler than meshes and will therefore be faster to rasterize. In addition, this will improve graph update performance, as colliders can be queried efficiently using the physics engine, while meshes cannot.
Reduce the bounding box of the graph to only cover the part of the world that you need.
Optimizing Navmesh Graph Scanning
How long it takes to scan a navmesh graph is almost entirely dependent on the number of triangles in the input mesh. If you can reduce that, then the graph will be scanned faster.
Optimizing Movement Scripts
Movement scripts can have a pretty big impact on performance. The different included movement scripts have different performance characteristics.
AILerp is the fastest, but the movement doesn't look very realistic, which may or may not be acceptable for your game.
AIPath is a bit slower, but it can handle local avoidance and has smoother movement (which may or may not be desirable).
RichAI is the slowest, but it is more robust than AIPath when following paths, and has better support for off-mesh links.
FollowerEntity is typically somewhere between AILerp and AIPath on the performance scale. It can use multithreading to avoid blocking the main thread, but it still does a lot of work behind the scenes and is more complex than the other scripts. It is currently in beta, but I still recommend it over both AIPath and RichAI in most cases.
You should also try to avoid having a CharacterController or Rigidbody component attached to your character, as they are quite slow. When none of these are attached, the AIPath and RichAI scripts will instead use a simple raycast to detect where the ground is, which is typically much faster.
Movement scripts for more details about the different movement scripts.
Optimizing Pathfinding
Pathfinding is often not actually a performance bottleneck. It only tends to become a bottleneck if you have a large grid graph and lots of agents. Use the profiler to see if the pathfinding threads are very busy.
However, even if the throughput is not a bottleneck, improving pathfinding latency can still be a good idea. Latency is the time it takes for a single path to be calculated after a path request has been issued. If you set the destination for a lot of agents all at once, a high latency can cause some agents to lag behind the others, as they have to wait for their turn to have their path recalculated.
In the above picture, you can see that the pathfinding threads become very busy recalculating paths for 210 agents, as they all received a new destination at the same time. However, the latency is still quite low, as all paths are calculated before the next frame even starts. So performance is fine in this case.
If you need to improve the pathfinding performance, here are some tips:
By far the easiest way is to enable multithreading (A* Inspector → Settings). This will make the pathfinding run on separate threads instead of on the Unity thread, which will likely improve performance quite a bit since almost all computers and even phones have many cores these days.
Logging path results has a pretty large performance impact. Often as much as reducing the pathfinding throughput by 50%. You should disable path logging if you do not need it. Set A* Inspector → Settings → Path Log Mode to None.
Reduce the frequency at which new paths are calculated.
Set the Recalculate Paths Automatically field on your movement script to Dynamic to make the agent recalculate its path less often when it is far from its target, and more often if it is closer, or if the target changed position a lot.
If you use the EveryNSeconds mode, try to increase the period field.
Perhaps you can even disable automatic path recalculation and use your own game-specific logic to recalculate the path only when necessary.
Use lower quality settings on modifiers. In particular, you might be able to reduce the number of segments that the SimpleSmoothModifier divides the path into if you are using it. The AIPath movement script already does a pretty good job at following the path smoothly, even if the path itself is not particularly smooth.
Using a recast graph instead of a grid graph will generally improve pathfinding performance, as recast graphs typically need much fewer nodes to cover the same area.
On a static map, heuristic optimization can be an option. See Heuristic Optimization.
More Tips
Take a look at the child pages for more ways to increase the performance.