Horde of NavMeshAgents - stops to recalculate path.


I’m making a simple horde-shooter, where a big amount of Agents run towards a moving player. I’ve made a Navmesh through build-in Unity baker.

All works well, but the problem is - on larger distances (the map is an outdoor ruins complex), all Agents are stopping every few frames/seconds when the Player is moving.


-It’s obvious they are recalculating the path to the Player, as their SetDestination is set on Invoke Repeating (repeating at 0.1-0.8 sec random range - so the Update doesn’t get clogged).

-The map is made in SketchUp and it’s a solid, complex, single model (consisting of two levels, catwalks, mazes etc).

-The NavMesh baking takes ~2-5 seconds as it is.


How can I speed up the path recalculating process on a big number (10-80) agents at once, so it’s as smooth as possible?

I know this is an old thread, but this could be useful for some people:
On your NavMeshAgent uncheck autobraking. This will not allow them to stop when recalculating the path.

Well, your question gives several clues as to places where performance could be improved

  • Sketchup is notorious for creating high poly-count meshes which are not really game-ready. If your navmesh is baked from that, it too is probably overly-complex and should instead be baked from a low-poly version of the mesh.

  • It’s good that you’re not recalculating paths every frame, but even every 0.1 seconds seems high to me. Why not recalculate every 2 seconds or so?

  • And is it realistic that all your agents have exact information to home in on the exact player location, even when they are at the other end of the level and perhaps are completely visually obscured? If an agent is far away, perhaps just get them to navigate to the approximate vicinity of the player (which wouldn’t require recalculation so often), and then only when they are close calculate the true path to the player.

  • In practice, few games calculate pathfinding for large numbers of individual agents, they’d use other techniques such as flow fields. It may simply be that you have to re-engineer your approach.

NavMesh.SetDestination is an asynchronous call but I don’t think it is multi threaded. So I am guessing if the core this is using gets maxed out then it throws stuff in a queue and “gets around to it” when there is time/CPU.

My fix was to replace NavMesh.SetDestination with NavMesh.CalculatePath. Create a new path, set your agent to the new path and update the path periodically with NavMesh.CalculatePath. This is not asynchronous and you might lose a little performance.

Now your agents will not stop when system is taxed. Also, you can rely on the path and time the agent takes to get to the destination being consistent. Thinking of “Tower Defence” games where this would be critical.

With the help of the answer of Foulcloud and the unity documentation page about NavMesh.CalculatePath I came up with something like this script, that seems to work pretty well for a tower defence game I’m working on. The only thing you need to change to make the agent move to a new destination is changing the destination variable to something new, for instance in a coroutine:

using UnityEngine;
using System.Collections;
using UnityEngine.AI;

public class Agent : MonoBehaviour
public Transform target;
public float pathUpdateFrequency = 2.0f;

private NavMeshAgent navMeshAgent;
private NavMeshPath path;
private float elapsed;
private Vector3 destination;

void Awake ()
	navMeshAgent = GetComponent<NavMeshAgent>();

void Start ()
	path = new NavMeshPath();
	elapsed = pathUpdateFrequency;


void Update ()
	elapsed += Time.deltaTime;
	if (elapsed > pathUpdateFrequency)
		elapsed -= pathUpdateFrequency;
		NavMesh.CalculatePath (transform.position, destination, navMeshAgent.areaMask, path);
		navMeshAgent.SetPath (path);

	for (int i = 0; i < path.corners.Length - 1; i++)
		Debug.DrawLine (path.corners *, path.corners [i + 1], Color.red);	*
  •   }	*
  • }*
  • IEnumerator TravelToDestination ()*
  • {*
  •   print ("Traveling towards destination..");*
  •   destination = target.position;*
  •   while (Vector3.Distance (transform.position, target.position) > 0.16f)*
  •   {*
  •   	yield return null;*
  •   }*
  •   navMeshAgent.Warp(destination);*
  •   print("Reached destination!");*
  • }*