Search Unity

remainingDistance issue

Discussion in 'Navigation' started by hellobard, Jul 1, 2016.

  1. hellobard

    hellobard

    Joined:
    Sep 26, 2012
    Posts:
    140
    Hi,

    I'm having a strange issue with remainingDistance, where the navmesh agent doesn't seem to be calculating the distance correctly. I have 6 enemies being spawned at the same time, and they are each assigned random waypoints. Two of the waypoints seem hard to get to, but they still are possible according to NavMeshPathStatus, so what happens is that two of my enemies don't move from their spawn point and an if statement checking that the remainingDistance is below 0.1f fires off a function that makes the enemy start firing.

    It seems like there's some sort of timing issue here, because if I remove the arrivedAtWaypoint in the if statement, the enemies can all get to their waypoints without a problem.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using DG.Tweening;
    4.  
    5. public class EnemyMovement : MonoBehaviour {
    6.  
    7.     [Header("Settings")]
    8.  
    9.     public float rotationSpeed = 20.0f;
    10.     public bool HasRagdoll = false;
    11.     public bool HasAnimation = false; // temporary solution for characters with no animations yet
    12.     public float sinkSpeed = 2.0f;
    13.  
    14.     [Header("Nav Mesh")]
    15.     NavMeshAgent nav;
    16.     public float DistanceToMyWaypoint = 0;
    17.     public bool IsNavigating = true;
    18.     public bool IsAttacking = false;
    19.     public bool arrivedAtDestination = false;
    20.     public bool DistanceToMyWaypointIsInfinity = false;
    21.     public bool CanReachMyWaypoint = false;
    22.  
    23.     public Transform myWaypoint;        // the waypoint
    24.     private Transform myTransform;
    25.  
    26.  
    27.     [Header("Connections")]
    28.     // scripts
    29.  
    30.     public Transform targetPlayer;
    31.     public Transform EnemyGun;
    32.     public Animator EnemyAnimator;    // The mecanim animator
    33.     public HashIDs hash;
    34.     public EnemyFire enemyFireScript;
    35.  
    36.  
    37.  
    38.     void Awake () {
    39.  
    40.         targetPlayer = GameObject.FindGameObjectWithTag ("Player").transform;
    41.         nav = GetComponent <NavMeshAgent> ();
    42.         myTransform = transform;
    43.         hash = GameObject.Find("GM_Enemies").GetComponent<HashIDs>();
    44.  
    45.     }
    46.  
    47.  
    48.     void Start () {
    49.        
    50.         StartNavigating();
    51.  
    52.  
    53.  
    54.     }
    55.    
    56.     void Update () {
    57.  
    58.  
    59.         // checks if the target has arrived at its waypoint
    60.  
    61.         if (IsNavigating) {
    62.  
    63.             DistanceToMyWaypoint = nav.remainingDistance;
    64.  
    65.             DistanceToMyWaypointIsInfinity = System.Single.IsNaN (DistanceToMyWaypoint);
    66.  
    67.             if(!arrivedAtDestination ){
    68.  
    69.            
    70.  
    71.                    
    72.                 if (nav.remainingDistance < 0.01f && myWaypoint != null && !DistanceToMyWaypointIsInfinity && CanReachMyWaypoint){
    73.                        
    74.                     Debug.Log ("I HAVE ARRIVED!");
    75.                     arrivedAtWaypoint ();
    76.                    
    77.                 }
    78.             }
    79.         }
    80.  
    81.  
    82.  
    83.  
    84.         if (IsAttacking && arrivedAtDestination) {
    85.  
    86.             Vector3 targetPostition = new Vector3( targetPlayer.position.x,
    87.                 this.transform.position.y,
    88.                 targetPlayer.position.z ) ;
    89.             myTransform.LookAt(targetPostition);
    90.  
    91.             //myTransform.rotation = Quaternion.Slerp(myTransform.rotation, Quaternion.LookRotation(targetPlayer.position - myTransform.position), rotationSpeed * Time.deltaTime);
    92.             EnemyGun.rotation = Quaternion.Slerp(EnemyGun.rotation, Quaternion.LookRotation(targetPlayer.position - EnemyGun.position), rotationSpeed * Time.deltaTime);
    93.  
    94.         }
    95.  
    96.     }
    97.  
    98.     public void setWaypoint(GameObject nextWaypoint) {
    99.    
    100.         myWaypoint = nextWaypoint.transform;
    101.    
    102.     }
    103.  
    104.     public void StartNavigating () {
    105.  
    106.         NavMeshPath path = new NavMeshPath();
    107.         bool hasFoundPath = nav.CalculatePath(myWaypoint.position, path);
    108.  
    109.         if(path.status == NavMeshPathStatus.PathComplete)
    110.         {
    111.             print("The agent can reach the destination");
    112.             CanReachMyWaypoint = true;
    113.  
    114.             if (targetPlayer != null) {
    115.                 nav.SetDestination (myWaypoint.position);
    116.                 //nav.destination = myWaypoint.position;
    117.             }
    118.         }
    119.         else if(path.status == NavMeshPathStatus.PathPartial)
    120.         {
    121.             print("The agent can only get close to the destination");
    122.             CanReachMyWaypoint = false;
    123.  
    124.             if (targetPlayer != null) {
    125.                 nav.SetDestination (myWaypoint.position);
    126.                 //nav.destination = myWaypoint.position;
    127.             }
    128.         }
    129.         else if(path.status == NavMeshPathStatus.PathInvalid)
    130.         {
    131.             print("The agent cannot reach the destination");
    132.             print("hasFoundPath will be false");
    133.             CanReachMyWaypoint = false;
    134.  
    135.         }
    136.  
    137.  
    138.     }
    139.  
    140.     void arrivedAtWaypoint () {
    141.    
    142.         IsNavigating = false;
    143.  
    144.         arrivedAtDestination = true;
    145.         nav.Stop();
    146.         nav.enabled = false;
    147.         nav.updatePosition = false;
    148.         nav.updateRotation = true;
    149.  
    150.         // animation
    151.  
    152.         IsAttacking = true;
    153.         enemyFireScript.isAttacking = true;
    154.            
    155.     }
    156.  
    157.  
    158. }
    159.  
    160.  
     
  2. calebc01

    calebc01

    Joined:
    Jul 21, 2015
    Posts:
    62
    Unfortunately, Unity's Nav Mesh Agent is a black box with few details exposed. My guess is that after calling SetDestintion on your nav agent, there is additional work that the nav mesh agent has to do later, probably in an internal Update() call. If your Update() is being called first, it may be that the remaining distance is 0 because the nag agent is still undergoing initialization.

    For example, I do know that one of the first things that happens to a Nav Mesh Agent on creation is that it gets snapped to the nav mesh. Perhaps this happens in an Update() call, before a path is finally applied.

    Try checking the following nav agent member variables - maybe one of them will have information about the state:

    pathPending
    isActiveAndEnabled
    isOnNavMesh

    You could also look at your own waypoint position and make sure the distance is *actually close to zero before stopping navigation.

    As an aside, note that you are actually computing the entire path twice, once using CalculatePath, and once using SetDestination. Instead, you can use SetPath() after CalculatePath() to avoid recomputing the path in the same function call.
     
    Novack and laurentlavigne like this.
  3. hellobard

    hellobard

    Joined:
    Sep 26, 2012
    Posts:
    140
    Thank you very much for the answer (and so sorry for the late reply!)!

    That was very helpful and thanks for the tip on the double path calculation :)