Kyle Banks

Synchronizing Idle, Walk and Run animations with a NavMeshAgent in Unity

Written by @kylewbanks on Aug 12, 2020.

Unity has a built-in navigation system which allows you to quickly develop levels and terrains which support automated AI pathfinding. Once your level or terrain is setup with a NavMesh you can easily add a NavMeshAgent component to your non-player character(s) and have them move around intelligently throughout your game.

The NavMeshAgent component prepares the NPC with steering properties like speed, acceleration and stopping distance, as well as obstacle avoidance parameters so you can finely tune your NPC behaviors.

One thing that doesn’t work out of the box is synchronizing with an Animator so you can have your character walk, run, and idle animations playing as they move about the scene.

Keeping your NavMeshAgent and Animator synchronized is pretty easy though, so don’t worry. This post will show you how I’ve set this up in the untitled game I’m currently working on, and show you the in-game results.

Okay, so here’s the scene without the animation system synchronized to the NavMeshAgent. In this scene the girl is expected to walk down the hill, turn and say something to the dog, and then run off down the road. As you can see the actions are correct but the look is pretty bad without animations:

This character is an NPC and all the movement is done through the NavMesh and NavMeshAgent systems along with a custom NPC scripting tool I’ve developed to give her a predefined script of actions and behaviors for scenes such as this. Go here, say this, look at this object, now go over there… that kind of thing. It’s not important for the result of this post, I’m just trying to paint a picture of how this all fits together.

There’s nothing particularly interesting or unique about the settings I use on the NavMeshAgent but here’s a look at the settings anyhow:

Mostly standard settings on the NavMeshAgent

The character is also setup with an Animator component, with a Movement state which consists of a Blend Tree to blend between the idle, walking and running animations based on a float WalkSpeed parameter.

Animator Blend Tree setup for use with the NavMeshAgent

With the Blend Tree setup like this, the character will animate with the following conditions:

  1. If the WalkSpeed parameter is less than 0.05 then the Animator will use the Idle animation
  2. A WalkSpeed of 0.05 to 4.0 will blend between the Walk and Run animations, moving more towards the Run animation as WalkSpeed increases
  3. A WalkSpeed above 4.0 will solely use the Run animation

Synchronizing the NavMeshAgent with the Animator

With a NavMeshAgent ready to go and the Animator setup like I have it above, all that’s left is to update the WalkSpeed parameter based on the speed of the NavMeshAgent. For this I’ve created a new NavMeshAgentAnimator component:

using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(Animator), typeof(NavMeshAgent))]
public class NavMeshAgentAnimator : MonoBehaviour 
{

    private static int ANIMATOR_PARAM_WALK_SPEED = 
    	Animator.StringToHash("WalkSpeed");

    private Animator _animator;    
    private NavMeshAgent _agent;

    private void Awake() 
    {
        this._animator = this.GetComponent<Animator>();
        this._agent = this.GetComponent<NavMeshAgent>();    
    }

    private void LateUpdate() 
    {
        float speed = this._agent.velocity.magnitude;
        this._animator.SetFloat(ANIMATOR_PARAM_WALK_SPEED, speed);        
    }
}

First we get a reference to the Animator WalkSpeed parameter using the static Animator.StringToHash function. This just gives you an integer value to use for animator.Set functions rather than a string, which is a little more efficient.

Next in Awake it’s just a matter of getting references to the Animator and NavMeshAgent components.

Finally, in LateUpdate we use the magnitude of the NavMeshAgent velocity as the speed parameter and set that on the Animator using the SetFloat function along with the integer parameter ID.

Add this component to your character and with everything hooked up, here’s the final result:

As you can see, it looks much better with the animations synchronized!

Let me know if this post was helpful on Twitter @kylewbanks or down below!