Navmeshagent runs in circles

I’m working on a game in which an NPC chases the player character. The NPC is a Navmeshagent and I’ve modified the Agent.cs script that comes with one of the Unity projects. The NPC behaves properly most of the time, but if the Player character runs into the NPC, the NPC can start to run around in circles. Eventually, after spinning around for a while, the NPC will seem to find its bearings and again pursue the character, but this can take 5-10 seconds.

I’ve tried resetting the path and destination every 1/2 second (on the idea that maybe the path was getting screwed up), but that only seemed to make things worse. And, when I did that, I did check to see that pathPending was false so the NPC at least thinks it knows where to go.

Here’s the bulk of code that I think is relevant (from the Agent.cs script); SetupAgentLocomotion gets called in Update.

protected void SetupAgentLocomotion()
{
	//Debug.Log ("Calling SetupAgentLocomotion.");
	bool attacking = animator.GetBool("Attacking");
	
	
	if (AgentDone() || attacking)
	{
  		
	    Vector3 diff = gameObject.transform.position - target.transform.position;

	    npc.transform.LookAt(target.transform.position);

                 locomotion.Do(0, 0);

                 if (!attacking) { StartCoroutine(Attack ()); }
	}
	else
	{

		if (float.IsNaN(agent.remainingDistance) || float.IsInfinity(agent.remainingDistance)) {
			agent.ResetPath();
			agent.SetDestination(target.transform.position);
		}
		
		float speed  = agent.desiredVelocity.magnitude;

		Vector3 velocity = Quaternion.Inverse(transform.rotation) * agent.desiredVelocity;

		float angle = Mathf.Atan2(velocity.x, velocity.z) * 180.0f / 3.14159f;

                    locomotion.Do(speed, angle);

	}
	
}

IEnumerator Attack() {
	timeOfLastAttack=Time.time;
	animator.SetBool("Attacking",true);

	if (TargetInRange()) {
		// this assumes using Target empty GO
		target.parent.SendMessage("Damage",DAMAGE_INFLICTED);
	}

            yield return new WaitForSeconds(1.0f * ATTACK_DELAY);
	animator.SetBool("Attacking",false);
	agent.SetDestination(target.transform.position);

}

I’ve been struggling with this for a while, so any insight anyone has would be extremely welcome. Sorry if the code formatting is a bit weird – after several edits it still isn’t quite right.

Thanks in advance.

Your NavMeshAgent has probably some angular speed. Thus it is not possible to walk around in arbitrary small turning circles. When approaching the target in a weird angle it will try to turn (while still walking) with its maximum angular speed, which is not enough to make a steeper turn.

So either you increase the angular speed which might look unnatural or you implement something like “FaceBeforeMoveAngle” where you first check whether the angle is smaller than a certain value before the agent starts moving. Otherwise it will only turn.

For my agent it looks roughly like this:

Vector3 velocity = Quaternion.Inverse(agent.transform.rotation)
    * agent.Agent.desiredVelocity;
float angle = Mathf.Atan2(velocity.x, velocity.z) * 180.0f / Mathf.PI;

float speed = agent.Agent.desiredVelocity.magnitude;

if (angle > agent.FaceBeforeMoveAngle) {
    agent.Do(0, angle);
} else {
    agent.Do(speed, angle);
}

You would compute the FaceBeforeMoveAngle everytime you change the agents destination.
I’m using that extra agent variable because I’m working with an Entity-System architecture. So just remove it and work directly on the NavMeshAgent if you want to.

I solved it setting stoppingDistance anything higher than 0.