Search Unity

Question How to stop root motion driven agent from overshooting NavMeshAgent bounds?

Discussion in 'Navigation' started by trzy, Mar 29, 2023.

  1. trzy

    trzy

    Joined:
    Jul 2, 2016
    Posts:
    128
    Hi,

    I have a character with a NavMeshAgent that uses said agent to move around. The blend tree forward speed variable ranges from [-2,2], where 0 is idle, 1 is walking, 2 is running. So I've set my agent speed to 2 when I want running behavior.

    However, when stopping, because I am actually using root motion to position the character, he oversteps the position of the NavMeshAgent. This is not a problem while running because I force agent.nextPosition to be the current root position:

    Code (csharp):
    1.  
    2. private void OnAnimatorMove()
    3. {
    4.     Vector3 rootPosition = _animator.rootPosition;
    5.     rootPosition.y = _agent.nextPosition.y;
    6.     transform.position = rootPosition;
    7.     _agent.nextPosition = rootPosition;
    8. }
    9.  
    But when we hit the edge of the navmesh, the agent position will remain on the NavMesh and we overshoot. See the below photo. This does not happen when stopping within the NavMesh because I force the agent position to match the character position. Only at the edges is it impossible for the agent position to follow because the character has animated past the navmesh.

    upload_2023-3-29_14-7-35.png

    I've tried matching the agent speed to the run state's average speed but this doesn't have any effect.

    My question is similar to this one but the answer there doesn't seem to solve the issue or even be directly applicable. I can't set velocity because if did that, there would be no motion at all (the animation initially has 0 velocity itself when in the idle state). I want to drive the animation blend tree using the NavMeshAgent velocity. And even if I was able to devise a way to set the agent velocity based on the animation, that wouldn't help the agent steering logic slow down rapidly enough.

    Thanks,

    -- B.
     
  2. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    650
    Rigidbody, CharacterController, Animator with Root Motion, Custom Scripts, NavMeshAgent all of them are ways to move a Transform around. If you use multiple at the same time, they might not work well together, it's best to just use one of them.
    As far as I can tell (from your code), you want the animator to control your CharacterTransform (actually your custom script but you're basically doing the same thing as the Animator, just with setting the height from the NavMesh). The Animator doesn't care about collisions, the navmesh or anything else. I guess the NavMeshAgent handles rotation and the root motion the forward movement.

    You can keep it that way if you want to. But you have to tell your animation to stop to stop the character, so you have to know when to stop. And to do that, you can use NavMeshAgent.remainingDistance. If you are close to the destination, tell your animator to switch to idle.

    In my previos game I just set the NavMeshAgent maxVelocity to a very low value and passed the (multiplied) velocity into the Animator with RootMotion.

    Both approaches work fine when setup correctly. If you have any questions, feel free to ask.
     
    Last edited by a moderator: Apr 18, 2023