Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug NavMeshAgent jumping in direction after clearing Path.

Discussion in 'Navigation' started by logane616, May 19, 2020.

  1. logane616

    logane616

    Joined:
    Jan 13, 2016
    Posts:
    1
    Hello, people of the internet. I have a strange issue that's been bugging me for a few hours that I can't seem to find a solution for. I have a NavMeshAgent with the functions LookAround(), Investigate(), and MoveTo(). The issue arises when the agent looks around.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5. using UnityEngine.XR.WSA.Input;
    6.  
    7. public class GhostAI : MonoBehaviour
    8. {
    9.  
    10.     NavMeshAgent agent;
    11.  
    12.     bool patrolArea;
    13.     bool lookAround;
    14.  
    15.     bool canRotate;
    16.  
    17.     IEnumerator rotCooldown;
    18.  
    19.     void Start()
    20.     {
    21.         agent = GetComponent<NavMeshAgent>();
    22.         patrolArea = false;
    23.         lookAround = false;
    24.         canRotate = true;
    25.     }
    26.  
    27.     public void MoveTo(Transform point)
    28.     {
    29.         agent.ResetPath();
    30.         agent.updatePosition = true;
    31.         agent.destination = point.position;
    32.     }
    33.  
    34.     public void OverrideDestination()
    35.     {
    36.         agent.ResetPath();
    37.     }
    38.  
    39.     public void Investigate(Transform point)
    40.     {
    41.         MoveTo(point);
    42.         patrolArea = true;
    43.     }
    44.  
    45.     public void LookAround(float seconds)
    46.     {
    47.         lookAround = true;
    48.         agent.ResetPath();
    49.         StartCoroutine(LookTimer(seconds));
    50.     }
    51.  
    52.     IEnumerator LookTimer(float seconds)
    53.     {
    54.         yield return new WaitForSeconds(seconds);
    55.         StopCoroutine(rotCooldown);
    56.         agent.isStopped = true;
    57.         agent.ResetPath();
    58.         lookAround = false;
    59.         canRotate = true;
    60.         agent.updatePosition = true;
    61.  
    62.         Debug.Log("Exited with LookTimer()");
    63.     }
    64.  
    65.     // Cools down after rotating the ghost
    66.     IEnumerator RotCooldown(float seconds)
    67.     {
    68.         yield return new WaitForSeconds(seconds);
    69.         agent.isStopped = true;
    70.         agent.ResetPath();
    71.         agent.updatePosition = true;
    72.         canRotate = true;
    73.  
    74.         Debug.Log("Exited with RotCooldown()");
    75.     }
    76.  
    77.     void LateUpdate()
    78.     {
    79.         // If the ghost should investigate
    80.         if (patrolArea)
    81.         {
    82.             // If the ghost has reached their destination
    83.             if (!agent.pathPending && agent.remainingDistance <= 0.5f)
    84.             {
    85.                 patrolArea = false;
    86.                 LookAround(Random.Range(3f, 4.5f));
    87.             }
    88.         }
    89.  
    90.         // If the ghost should look around
    91.         if (lookAround)
    92.         {
    93.             Debug.Log("Alert");
    94.             if (canRotate)
    95.             {
    96.                 Debug.Log("Alert");
    97.                 canRotate = false;
    98.                 agent.updatePosition = false;
    99.                 agent.destination = Random.insideUnitCircle.normalized;
    100.  
    101.                 rotCooldown = RotCooldown(Random.Range(1f, 2f));
    102.                 StartCoroutine(rotCooldown);
    103.             }
    104.         }
    105.     }
    106.  
    107. }
    108.  
    Here's how I have the AI investigate. When Investigate is called, it is passed a transform. The agent will then move to the position of this transform, and once it gets extremely close it will call ResetPath() and LookAround(). LookAround() will set the variable lookAround to true and start the LookTimer() Coroutine. When lookAround is set to true the LateUpdate() function will set the agent's destination to a random vector using insideUnitCircle. To make this affect only the agent's rotation, I disable agent.updatePosition.

    The RotCooldown() function is similar to LookTimer() but it just allows the agent to change directions several times.

    The issue occurs after LookTimer() has completed the countdown. All LookTimer() does is clear the current Path, reset the variables that LateUpdate() uses for checks, and set agent.updatePosition to true again, that way the agent will move to it's next destination and not just rotate towards it. On the frame that LookTimer() finishes the agent will jump to the destination set by Random.insideUnitCircle, even though I have stopped the agent and cleared the path. I don't understand why this is happening.

    The reason I am having the agent look around in this method is to avoid using multiple types of movement (i.e. NavMesh combined with changing transform.localRotation directly). If there is a better way to have the agent look around that solves this issue please let me know.