Creating navmesh and agents in Unity

The aliens have arrived, but they’re little more than decorations at this point. They need to get moving! It seems like an easy enough task, yes? You could set a target for the aliens, and in each frame move them towards the target. Problem solved. End of chapter!

Of course, it’s not that easy. First, you’d have to rotate the alien constantly so it faces the space marine. Second, a real problem occurs when an alien runs into a column. The aliens will keep walking into the column until something causes them to move in a different direction. It’s pretty ridiculous when a single column can block an entire mob.

Perhaps you could get away with this behavior 20 years ago, but modern gamers expect better than this.

Your first inclination may be to write the pathfinding code. For instance, you could write code that makes the aliens turn and move until they are free of the column, then redirect them towards the hero.

It’s not that it wouldn’t work, but you’d be treating a fundamental problem like an edge case. What would happen if you added another floor to the mix? You’d have to apply similar fixes, and then your code quickly becomes an unreadable pile of spaghetti. Thankfully, there’s a better way.

Note: This tutorial is part of a collection that teaches Unity development from the ground up. You can read the entire series over here. This series is free and does not require any account creation. All assets are provided. If you find it useful, feel free to buy me a coffee.

Unity’s navigation system

It turns out Unity has pathfinding solutions you can use right out of the box, through its navigation system. Four objects comprise the navigation system:

  • NavMesh: Represents walkable areas. This works on flat and dimensional terrain, such as stairs.
  • NavMesh Agent: The actor or agent using the NavMesh. You give your agent a goal and it will find its way using the NavMesh.
  • Off-Mesh Link: A shortcut that can’t be represented on the map, such as a gap that characters can actually cross.
  • Off-Mesh Link: A shortcut that can’t be represented on the map, such as a gap that characters can actually cross.

To get the aliens to chase the hero, you first need a NavMesh over the entire floor to designate it as a walkable area. To get started, click GameObject AI NavMesh Surface.

This shows the NavMesh Surface selected in the AI category.

This creates a new NavMesh surface for your agents, but you can’t use it just yet. You have to bake it. A baked surface is an optimization. It means it is not dynamic. Basically, Unity analyzes your mesh and saves it.

With the NavMesh Surface selected, click the Bake button in the Inspector.

This shows the bake button selected on the NavMesh surface

You’ll notice everything is now light blue. This means you’ve created a walkable surface. Some surfaces should not be walkable. For instance, the top of the area is bright blue as well as the columns. You need to remove them from the mesh.

This shows the completed NavMesh covering the entire arena.

Select the Outer Wall.001 GameObject. You can find this as a child in the BobbleArena or just search for it in the Hierarchy. Click the Add Component button. In the Navigation category, select NavMesh modifier.

This demonstrates the NavMesh modifier with the mode set to Remove Object.

This component determines how the GameObject will interact with the rest of the NavMesh. For the Mode, change it to Remove Object.

Now select your NavMesh surface again, and press the Bake button. You’ll see the surface is removed. Do this for all the walls and columns. When you are finished it will look like this:

This shows the NavMesh just on the ground.

Creating agents

You have the mesh, so now you need agents. Select the Alien prefab in the Prefabs folder. Click Add Component then click NavMesh Agent in the Navigation category. You have many options here:

This is a screenshot of the NavMesh Agent component.

The Agent Type is currently set to Humanoid. When working with dynamic NavMeshes, you can also have dynamic agent types. For your game, you’ll use a fixed type.

The Base offset is the difference between the center of the agent and the center of the GameObject. Since the two are the same, leave it at 0.

Underneath that section, you’ll notice an Obstacle Avoidance section. Set Radius to 1.45 and Height to 6.2.

Quality determines how the path will be defined. At the highest quality, the path will be determined according to obstacles and other agents. At the lowest quality — none — the path will ignore agents and merely try to avoid immediate collisions.

Since there are many agents in play, set the Quality to Low Quality to reduce CPU time for calculating the paths.

You can see visual representations of these figures in the Scene view where a green cylinder defines the agent’s bounds.

This shows the cylindrical colliders for the NavMesh agent

At this point, you’ve configured the NavMesh Agent, and this new component will drive your GameObject. However, there’s a Rigidbody attached. Since the Rigidbody won’t be controlled by physics, check the Is Kinematic checkbox in the Alien Prefab.

Writing the agent code

Now you need to set the agent’s goal. On the Alien Prefab, click the Add Component button then click New Script and name it Alien. Open it in your code editor.

First, you need access to the NavMeshAgent classes. Underneath the using statements, add the following:

using UnityEngine.AI;

Add the following variables underneath the opening class brace.

public Transform target {get;set;}
private NavMeshAgent agent;

The target is where the alien should go. In this case, you’re using a property as you’ll be setting this property in code.

Also notice the variable name doesn’t reference the hero. You don’t always want the aliens to chase down the hero. For instance, the hero might throw a noisemaker to attract aliens to a certain area and then mow them down, or maybe he’ll get a powerup that makes the aliens turn on each other.

By making the enemies’ goal a target instead of a certain character, you leave yourself open to more game design opportunities.

Next, add the following to Start():

agent = GetComponent<NavMeshAgent>();

This gets a reference to the NavMeshAgent so you can access it in code. Now, in Update(), add the following code:

agent.destination = target.position;

Save the file and switch over to GameManager.cs to set the target for the alien.

Return to where you left off in Update(), and add the following code just after the line that sets newAlien.transform.position:

Alien alienScript = newAlien.GetComponent<Alien>(); 

This gets a reference to the Alien script. Now, add:

alienScript.target = player.transform;

This sets the target to the space marine’s current position.

Finally, the alien should rotate towards the hero right after being spawned. Otherwise, it’ll squander time by rotating instead of attacking. Add this:

Vector3 targetRotation = new Vector3(player.transform.position.x,  
  newAlien.transform.position.y, 
  player.transform.position.z);
newAlien.transform.LookAt(targetRotation);

This code rotates the alien towards the hero using the alien’s y-axis position so that it doesn’t look upwards and stare straight ahead.

Save and play your game. Try it out. Things aren’t exactly as planned.

Fixing the agents

When you play the game, you’ll notice a few issues.

  1. There are a ton of errors in the console.
  1. The aliens move crazy slow.
  1. The aliens walk through the columns.

Start with the first issue. You should see the following in the console:

This shows the console filled with errors

If you only see one log message, you may have the console set to Collapse. The collapse option groups all repeating messages into one statement. The number after the log message indicates the amount of log messages that have been grouped.

This shows the Collapse option on the console along with the error count.

The error message states that no variable target was assigned to the alien, i.e., one of the aliens doesn’t have a reference to the space marine. This is an easy fix. Open Alien.cs in your code editor, and then change Update() to match the following:

if (target != null) 
{
  agent.destination = target.position;
}

Now run your game and check if the console is clear. If not, make sure to click the Clear On Play option.

This shows the Clear on Play in the console.

You successfully resolved the console errors, but you merely addressed the symptoms. Why did you get console errors in the first place?

Play the game again and watch the aliens carefully. You’ll see all but one of them milling about. You dragged this non-moving alien into the scene a while back — it wasn’t created by the GameManager. Hence, it has no target and the GameManager doesn’t know about it.

This seemingly small issue has the potential to break the balance of your game. To fix this, find the alien in the hierarchy and delete it. Buh-bye little orphan alien!

Move on to the second issue: Slow-moving aliens. Thankfully, this is an easy fix. It’s part of the NavMeshAgent properties.

In the Project browser, select the Alien from the Prefabs folder. You’ll see that the NavMeshAgent component has a section called Steering. Here’s the breakdown:

  • Speed: How fast the agent moves in world units per second. Set this to 20.
  • Angular Speed: Determines rotation speed in angles per second. Set this to 120 (the default value).
  • Acceleration: How fast the agent increases speed per second. Set this to 15.5.
  • Stopping Distance: How close the agent stops near its goal. Set this to 0 (the default value).
  • Auto Braking: Slows the agent as it approaches its goal. Uncheck this.
This shows all the steering options for the NavMesh Agent.

Those values were obtained simply by play testing the game at a base difficulty. Later, as the gameplay progresses, you may want to alter those values to make the game easier or harder.

Play your game. Now the aliens will move with purpose.

Creating obstacles

Now for the last problem: The little buggers can’t just walk through the columns. In the Project window, select the BobbleArena-Column in the Prefabs folder. Click the Add Component button. Select NavMesh Obstacle in the Navigation category.

This works just like a plain old collider. Set the Shape to Box then Center to (0, 2.3, 0) and Size to (2.07, 4.27, 2).

This shows the column with a NavMesh obstacle collider attached

You’ll notice your columns gain a green wireframe that indicates the NavMeshObstacle. Run your game. Your aliens will now walk around the columns as opposed to phasing through them.

Where to go from here

It didn’t take much, you now have moving aliens who track the player across the arena. They’ll even avoid the columns now to make sure they snack on the space marine. Unfortunately, you are not done yet. There’s still more tweaking.

The current values are all out of whack right now. You’ll need to tweak some values and add some collision detection. You’ll do this in the next tutorial.


Discover more from Jezner Blog

Subscribe to get the latest posts sent to your email.

By Brian Moakley

Brian Moakley is a writer and editor who lives amongst the quiet hills in New England. When not reading tales of high adventure, he is often telling such stories to all who will listen.

Related Post

Leave a Reply