NPC AI Using the Navmeshes and NavMeshAgents
Recommended prior reading:
Arrays and ListsIn this session, we will be exploring the pathfinding functionality of Unity.
This allows us to have characters, typically known as NavMeshAgents, that can move around a space.
We will start by adding the package called ‘ProBuilder’. This is an easy way for us to produce grayboxed level environments.
In Unity, click on Window > Package Manager
Then, at the top, change the settings from Packages: In Project to Unity Registry:
Then search for, and install, ProBuilder
Now, back in Unity, click Tools > ProBuilder > ProBuilder Window
This window will open up:
Here we can quickly build an environment by clicking New Shape and drawing out some objects. I am going to recommend you create a ground (plane) with some walls and ramps:
Note: you can place cubes down and turn them into ramps using the edge select modes:
The planes and cubes etc that make up our environment need to be set to ‘Static’ in the inspector. This means they are expected to not change position at runtime. This allows us to more accurately using pathfinding around these objects.
Ensure ‘Static’ is ticked for all objects.
Next we need to make a NavMesh over the top of the environment. This essentially marks navigable space.
Click on Window > AI > Navigation.
This opens up the Navigation window:
Simply click Bake > Bake
The NavMesh, in blue, represents navigable space in our environment. Anywhere not in blue cannot be traversed.
With a NavMesh set up, let’s now create a character/actor to navigate it.
We can start by simply creating a capsule in the hierarchy.
Make sure your capsule has the default 1, 1, 1 scale:
Then, give this capsule the ‘NavMeshAgent’ component.
Next, let’s make a script and attach it to the capsule. I’m going to name my script ‘AI_Character’.
Let’s open up the script.
Firstly, we need to import the AI namespace by typing
using UnityEngine.AI;
This is done above the class declaration.
Next, we need to grab this object’s NavMeshAgent component, so we can give it commands. We do this using the usual GetComponent<> pattern:
Wherever you are declaring class-wide variables:
NavMeshAgent nav;
Inside the Start()
message:
nav = GetComponent<NavMeshAgent>();
We grab this object’s NavMeshAgent component, and put it into our instance called nav
.
Now, we can give the component commands using the functions and variables built into the NavMeshAgent component when we type nav
.
Next, we need to set up a way for our NavMeshAgent to find a thing to move towards. Let’s use a cube as our target.
In the class, declare the following variable:
[SerializeField] Transform navTarget;
This is going to save information about which point in space we are going to move towards. It will be public, so it will be accessible in the Unity Editor:
Make some cube object that will serve as our target and drag it into this field that says None.
Finally, we need to make our NavMeshAgent character move towards the target. We can do this using the function of NavMeshAgent called SetDestination. In our Update() message, we can type:
void Update()
{
nav.SetDestination(navTarget.position);
}
This will tell our NavMeshAgent to constantly set its target to wherever the object is saved inside of the ‘navTarget’ variable.
Some of you may be wondering how we deal with NavMeshes with moving objects to avoid. Consider a game like GTA - we need to ensure player character know to avoid cars, and these are clearly not static.
The solution is simple - we have a component called NavMeshObstacle:
By turning on Carve, this will delete parts of the NavMesh it overlaps with, in real time, ensuring that NPCs will not be able to access this.
Patrol/Wander Behaviour
In some instances, you might want to make an AI agent walk around a set/random path. We can do this fairly easily by creating an array of destinations to patrol to, and randomly choosing one of them to go to after we reach a destination.
We can do this by adding the brackets in from of the type of our navTarget variable:
[SerializeField] Transform[] navTarget;
In the editor, we are then able to control our array's length, as well as assign values to the array. In my example below, I have created three objects to be the destination of our patrol points and scattered them around a map.

Our logic in this case will be fairly simple.
In the beginning, move towards the first target object.
Then, when we are very close to the our destination, randomly choose another target and move towards that instead.
We can implement our code like so:
//An integer used to choose which patrol point to go to.
int patrolCounter = 0;
//Then, inside Update()...
//If the distance between where our character is and our destination is less than 0.1 units...
if (nav.remainingDistance < 0.1f)
{
//Pick a random number between 0 and the length of the target array.
patrolCounter = Random.Range(0, navTarget.Length);
//Move to our new target destination.
nav.SetDestination(navTarget[patrolCounter].position);
}
If you can implement this, try some of these additional challenges:
Combine up a character, for example from Mixamo, so that you have a walking, animated character.
Make a character wait at a patrol point before moving onto the next one.
Reference Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class AI_Character : MonoBehaviour
{
[SerializeField] Transform[] navTarget;
[SerializeField] int patrolCounter = 0;
NavMeshAgent nav;
void Start()
{
nav = GetComponent<NavMeshAgent>();
nav.SetDestination(navTarget[patrolCounter].position);
}
// Update is called once per frame
void Update()
{
if (nav.remainingDistance < 0.1f)
{
patrolCounter = Random.Range(0, navTarget.Length);
nav.SetDestination(navTarget[patrolCounter].position);
}
}
}
Further Reading:
Last updated