How can I tell when a navmeshagent has reached its destination?

Looked in the documentation and couldn’t find a somewhat simple solution that A* had. Is there a OnComplete() event or do I have to make one by determining remaining distance?

You have to be careful. A distance check isn’t always accurate since the steering behavior portion of the NavMeshAgent may actually still be working even if the distance is less than the stopping distance.

I found this worked best for me:

// Check if we've reached the destination
if (!mNavMeshAgent.pathPending)
{
    if (mNavMeshAgent.remainingDistance <= mNavMeshAgent.stoppingDistance)
    {
        if (!mNavMeshAgent.hasPath || mNavMeshAgent.velocity.sqrMagnitude == 0f)
        {
            // Done
        }
    }
}

I use this:
float dist=agent.remainingDistance;
if (dist!=Mathf.infinite && agent.pathStatus==NavMeshPathStatus.completed && agent.remainingDistance==0)
//Arrived.

You may want to check a few other conditions (pathInvalid, etc.)

In the Unity Documentation it says that remainingDistance is “The distance between the agent’s position and the destination on the current path”. I kept getting a zero for remaining distance so my workaround pathcomplete function was a bit different

protected bool pathComplete()
	{
		if ( Vector3.Distance( m_NavAgent.destination, m_NavAgent.transform.position) <= m_NavAgent.stoppingDistance)
		{
			if (!m_NavAgent.hasPath || m_NavAgent.velocity.sqrMagnitude == 0f)
			{
				return true;
			}
		}

		return false;
	}

One way to implement this mechanism is to place a GameObject on the destination (you probably used one as destination already), and add BoxCollider and a trigger. Once the object with the nav mesh agent collided with the destination game object, you can determine in the OnTriggerEnter() function and check if the colliding object is the one you want (use tag or name), and do your rest stuff.

Of course, you can attach a script on the destination object, so it will become transparent on game start, so no one would see them.

This isn’t much of an answer, but for other people who have the same question, yes Brenden you are correct. You’ll need to write your own. It might also be worth noting that sometimes myAgent.remainingDistance is not always accurate or available, so you may need to resort to using Vector3.Distance() as a backup.

I found using Vector3.Distance to be the most successful.

if(Vector3.Distance(transform.position, target.position) < 2){
     Debug.Log("At Destination");
}

if (agent.remainingDistance > 0 && agent.remainingDistance <= agent.stoppingDistance)
print (“Reached Safely”);

This is a very simple solution. Using a coroutine you can use WaitUntil like this:

Once you called agent.SetDestination (hit.point), call a coroutine like this

IEnumerator WaitUntilReachTarget(){		
		yield return new WaitForSeconds(0.025f);
		Debug.Log (agent.remainingDistance);
		yield return new WaitUntil(() => agent.remainingDistance == 0);
		Debug.Log ("ATTACK !!");
	}

public static bool ReachedDestinationOrGaveUp(this NavMeshAgent navMeshAgent) {
if (!navMeshAgent.pathPending) {
if (navMeshAgent.remainingDistance <= navMeshAgent.stoppingDistance) {
if (!navMeshAgent.hasPath || navMeshAgent.velocity.sqrMagnitude == 0f) {
return true;
}
}
}
return false;
}

// example usage (you can also use a co-routine instead)

public async void walkTo(Transform destination) {
  
  if (walking) { return; }

  walking = true;
  agent.destination = destination.position;

  await new WaitUntil(() => agent.ReachedDestinationOrGaveUp());
  walking = false;
}

I think if(_navMeshAgent.remainingDistance == 0) can solve your problem