Search Unity

Question Enabling NavMeshAgent on moving object causes speed loss

Discussion in 'Navigation' started by Peter77, Jan 23, 2021.

  1. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,619
    I have a moving object that travels at a constant speed without navigation. At some point, I turn on navigation and the moving object is then controlled by the NavMeshAgent.

    When I enable the NavMeshAgent, there is a very visible loss in speed, until the NavMeshAgent "catched up" again. I set the NavMeshAgent.speed to the same value that's used to move the object without NavMeshAgent. And turning off navigation also does not cause such speed difference glitch, so I guess it's something with the navigation system.

    Below you can find my test project. The cube just moves forward and every time I enable the NavMeshAgent, the speed loss occurs. How can I avoid that? I want that there is no visible glitch when turning on navigation.



    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5.  
    6. public class MovingObject : MonoBehaviour
    7. {
    8.     [SerializeField] NavMeshAgent m_Agent = default;
    9.     [SerializeField] Transform m_NavDestination = default;
    10.     [SerializeField] float m_Speed;
    11.  
    12.     void Update()
    13.     {
    14.         if (Input.GetKeyDown(KeyCode.Space))
    15.         {
    16.             if (!m_Agent.enabled)
    17.             {
    18.                 m_Agent.enabled = true;
    19.  
    20.                 NavMeshPath path = new NavMeshPath();
    21.                 NavMesh.CalculatePath(transform.position, m_NavDestination.position, ~0, path);
    22.                 m_Agent.SetPath(path);
    23.  
    24.                 //m_Agent.SetDestination(m_NavDestination.position);
    25.                 m_Agent.speed = m_Speed;
    26.                 m_Agent.acceleration = m_Speed;
    27.  
    28.                 if (m_Agent.pathPending)
    29.                     Debug.LogWarning("NavMeshAgent path is pending");
    30.             }
    31.             else
    32.             {
    33.                 m_Agent.enabled = false;
    34.             }
    35.         }
    36.  
    37.         if (!m_Agent.enabled)
    38.         {
    39.             transform.position += Vector3.forward * m_Speed * Time.deltaTime;
    40.         }
    41.     }
    42.  
    43.     void OnGUI()
    44.     {
    45.         GUI.matrix = Matrix4x4.Scale(Vector3.one * 2);
    46.  
    47.         GUI.Label(new Rect(10, 10, 500, 500),
    48.             $"Press SPACE to toggle\n"
    49.             + $"NavMeshAgent.enabled = {m_Agent.enabled}\n"
    50.             //+ $"NavMeshAgent.pathPending = {m_Agent.pathPending}\n"
    51.             );
    52.     }
    53. }
    54.  
     

    Attached Files:

    Last edited: Jan 30, 2021
  2. JBR-games

    JBR-games

    Joined:
    Sep 26, 2012
    Posts:
    708
    im guessing there is some time between when your object gets the agent turned on (which now controls movement) to when the agent actually moves. so you have a few things you could try. 1st have the navmesh agent as a seperate object that you could blend speed/location too..
    another is to get the current velocity before you turn on the agent and apply it to the agent by force.
    3rd is you can actually get a path from the navmesh without an agent at all. you can calculate it and then move your object as you see fit along the path. the bad thing with this option is that avoidance of other agents/objects does not work automatically and must programmed.
     
    Last edited: Jan 30, 2021
  3. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,619
    Thanks for your reply. The switch happens within the same frame and I think the NavMeshAgent starts moving immediately, just not at the correct speed.

    I'm not sure I can follow.

    In my case, you can think of Mario Kart. If the player collects a bullet powerup in Mario Kart, the Player loses control and the bullet AI takes over control. In Mario Kart the racing car is replaced with a bullet model. In my case, the model doesn't change, it's still the racing car.

    It's an in-game event that can occur at any time where I need to take control away from the Player and let the AI take over. That's what I was trying to replicate in my test shown above. The cube (racing car) is controlled by the player (in this case it just moves forward at a constant speed to keep it simple), then the in-game event occurs (space-bar pressed) and the AI takes over the racing car controls.

    That's what I do, I set the speed and acceleration to the current speed, but the speed loss still occurs.

    I'm actually trying to avoid that and would like to use Unity's implementation instead.
     
  4. JBR-games

    JBR-games

    Joined:
    Sep 26, 2012
    Posts:
    708
    im not at my computer today to check demo. but have you set the agent acceleration to a very high number.. 1000 or more? even if navmesh agent.setDestination() call is made it will take a while to accecerate to the needed speed.
     
  5. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,619
    The velocity property was the missing piece of the puzzle. Setting velocity to
    Code (CSharp):
    1. m_Agent.velocity = transform.forward * m_Agent.speed;
    ... when enabling the NavMeshAgent solves the problem.