NavmeshAgent.remainingDistance remains at 0 but the agent still moves and behaves correctly
Asked Answered
P

5

0

Hello,

I’m having a rather weird bug with Unity’s navmesh system (I’m using Unity Free 4.2). Basically, the navmesh system itself works correctly, the unit goes from A to B and avoids the obstacles. However, sometimes if I try to log the remainingDistance variable as it moves it stays at zero the whole time. This is slightly annoying because I want to know whether the unit is moving so that I can draw its selectionbox at the right position (this is for a RTS game), and of course I’m using the “remainingDistance” variable to know when the unit has reached its destination.
What really confuses me is that for two identical units (same prefab, same script, same everything as far as I can tell), one will have the correct variable and the other one won’t. Even weirder, the units who are “bugged” still behave normally if I don’t let them stop. What I mean is, I tell unit 1 to go from A to B. It will bug out and say that remainingDistance is 0 despite it clearly moving (let me reiterate that even when I say a unit is “bugged”, it still moves around as expected so it’s not like the navmesh system itself doesn’t work). If I wait until it reaches B and then tell it to go to C, the same will happen -except the position will be recalculated once, at the time of the click-. But if I give it another order mid-moving, then suddenly it starts working normally. So if I keep giving it new orders it somehow works, but if it ever stops once, then it’s going to bug again until I give two orders in a row.

Now there are obviously hacky ways to solve it, such as treating any click as a double-click or issuing the command twice if the unit was not moving before. But it’s a dirty hack and I’d rather solve the problem than hide it with a hack. If it’s possible to solve it, that is.

Thanks in advance

Pyxidium answered 4/1 at 15:54 Comment(3)

Was wondering if you have solved this problem? I am also interested in the solution as I have the same problem with my project with the "remainingDistance" variable.

Riehl

Wow you must have looked for quite some time to find that forsaken post. Unfortunately, nope I never truly solved this problem. Then again I haven't worked on that project of mine for over a year. A bit concerning to see that the issue is still present with the newer versions, though I suspect it's the kind of bug that's also very hard to track down. Basically I think your best bet is to implement a small hack, either one of those I mentioned in the original post or find a new (perhaps cleaner) one. Please report on this thread if you ever find a definitive solution though!

Pyxidium

from my understanding remainingdistance is 0 because it is hitting every path if you get the object stuck then it should become higher than 0.

Jiles
B
0

Before you use the agent.SetDestination(POS) method, you may call the agent.ResetPath method, because I also encountered this problem, but I solved the problem. I’m Chinese.

Bulter answered 4/1 at 15:56 Comment(0)
S
0

It does not behave correctly. And ResetPath doesn’t solve the problem (for me).
Waiting a couple of frames (1 is not enough) after setting a new destination works.
The problem shows up in the tutorial “John Lemon’s Haunted Jaunt: 3D Beginner”:
The ghosts will keep turning around because remainingDistance < stoppingDistance.

Fix for WaypointPatrol.cs:

using System.Collections;
using System.Collections.Generic;
  
using UnityEngine;
using UnityEngine.AI;
  
public class WaypointPatrol : MonoBehaviour
{
  
	public NavMeshAgent navMeshAgent;
	public Transform[] waypoints;
	public bool LogTurns = false;
  
	int m_CurrentWaypointIndex = 0;
  
	int wait=0, waitTix=3;
  
	void Start()
	{
		navMeshAgent.SetDestination( waypoints[m_CurrentWaypointIndex].position );
		wait = waitTix;
	}
  
	void Update()
	{
		if (--wait > 0) return;
  
		if (navMeshAgent.remainingDistance < navMeshAgent.stoppingDistance)
		{
			m_CurrentWaypointIndex = (m_CurrentWaypointIndex + 1) % waypoints.Length;
  
			if (LogTurns)
				Debug.Log(this.gameObject.name + " new destination Index: "+m_CurrentWaypointIndex);
  
			navMeshAgent.SetDestination( waypoints[m_CurrentWaypointIndex].position );
			wait = waitTix;
		}
	}
}

As a complete noob this took a while to figure out - but I learned a lot : )

BTW: I’m using the Unity-2019-2.0f1

Sikh answered 4/1 at 15:56 Comment(0)
B
0

I’ve encountered the same problem and found another solution:

The NavMeshAgent has a property called pathPending which becomes false once the calculation of the path has finished. So inside the Update method I check for pathPending and only continue once pathPending is false.

Booker answered 4/1 at 15:58 Comment(0)
S
0

The reason for this issue is that pathfinding can be a tedious process, so to avoid lag the unity path system is using multithreading, to expand the calculation over multiple frames, and take advantage of the multiple cpu-cores even smartphones have nowadays. The issue now is that if you put agent.remainingDistance() in the update method, it will return 0 or the value prior to the agent.destination() call.

To avoid this, start the method with

if(agent.pathPending)
      return;

Then the call will be ignored until the path is calculated.

Schlueter answered 4/1 at 15:57 Comment(0)
U
0

Unfortunately, I get the same error. My goal is to have an enemy patrol between certain points in the scene with the Navmesh Agent. There is no problem if there is only one waypoint in the scene, but when I add two or more waypoints, the enemy object gets confused and confused about where to go.

When I print the Remaining Distance and Stopping Distance to the console, it turns out to be 0 even if the enemy object moves, that is, it goes towards the waypoint.

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;

public class ZombiePatrolingState : StateMachineBehaviour
{
    float timer;
    public float patrolingTime = 10f;

    Transform player;
    NavMeshAgent agent;

    public float detectionArea = 18f;
    public float patrolSpeed = 1f;

    List<Transform> waypointList = new List<Transform>();

    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // --- Inıtialization --- //

        player = GameObject.FindGameObjectWithTag("Player").transform;
        agent = animator.GetComponent<NavMeshAgent>();

        agent.speed = patrolSpeed;
        timer = 0;

        // --- Get all waypoints and Move to First Waypoint --- //

        GameObject waypointCluster = GameObject.FindGameObjectWithTag("Waypoints");
        foreach (Transform t in waypointCluster.transform)
        {
            Debug.Log(t);
            waypointList.Add(t);
        }

        Vector3 nextPosition = waypointList[Random.Range(0, waypointList.Count)].position;
        agent.SetDestination(nextPosition);

    }

    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // --- If agent arrived at waypoint, move to next waypoint --- //
        if(agent.remainingDistance <= agent.stoppingDistance)
        {
            Debug.Log("Remaining Distance: " + (agent.remainingDistance));
            Debug.Log("Stopping Distance:" + (agent.stoppingDistance));
            agent.SetDestination(waypointList[Random.Range(0, waypointList.Count)].position);
        }

        // --- Transition to Idle State --- //

        timer += Time.deltaTime;
        if(timer > patrolingTime)
        {
            animator.SetBool("isPatroling", false);
        }

        // --- Transition to Chase State --- //

        float distanceFromPlayer = Vector3.Distance(player.position, animator.transform.position);
        if (distanceFromPlayer < detectionArea)
        {
            animator.SetBool("isChasing", true);
        }



    }

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        // Stop the agent
        agent.SetDestination(agent.transform.position);

    }
}

Unimposing answered 4/1 at 15:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.