Welcome to part 3 of my pathfinding in Unity tutorial series. In the first two parts of this series, I looked at setting up a Unity navigation mesh in a scene, a NavMeshAgent that will use the navigation mesh to travel and then how to place obstacles to make the game world a lot more interesting. So with that complete, how do we then setup a basic navigation or route system that allows for our NavMeshAgent to run a basic partrol? Let’s put something together a rather simple and crude example.
Creating a Patrol Route
This tutorial starts with a basic scene that I’ve already put together that has a bunch of obstacles in place and builds a semi-interesting environment. However, we then need to build some method by which we can move between specific points in that environment. Now we can actually go so far as to automate this using items of interest in the world to infer specific locations to move towards. But for now, we’re going to place them by hand – acting as something of a level designer – and then will have our agent navigate through them. If you need help with how to build a navmesh, then head back to part 1 of the series, as well as part 2 if you want to add obstacles into the mesh.
A Waypoint Class
So I’m started by creating a simple class that stores information about a given waypoint. Namely it’s transform, but I also want to be able to draw to screen the location of these transforms when I have the DrawGizmo mode selected in the top-right of the game-view window of the Unity editor. If you’ve never used DrawGizmo, think of it as like your debug drawing tools you can have active in the scene to see how things are operating. Like using Debug.Log, except visually.
So here is a simple class that stores the transform of the gameobject (which is also our waypoint) as well as draws a wire sphere at a specific location.
With our Waypoint class in place, we can then place a variety of empty GameObjects complete with this Waypoint class attached to them. I have prepared the example shown in the image above, but feel free to put together any old configuration you feel like.
A Patrolling NPC
Then the next trick is to add extra functionality so that our character will then patrol around a variety of these waypoints. Now there are multiple ways to go about this, you could select a waypoint at random, which is fine, but ultimately it means that the character will look a little less realistic if they’re suddenly changing their mind and going from locations next to one another and suddenly to one on the other side of the map.
So what I have opted for is a version that will simply iterate through a pre-determined list of positions, that – with a certain probability – can then decide to change direction.
Now I already prepared the code shown below. I’m going to focus on walking through what I have done and how it works, it’s all rather straight forward.
First up, the code maintains the list of way points that we can move between and uses them to select between them. It also carries variables for whether we wait at a node, how long we wait at the node and whether we switch direction using a probability.
The Start() method is essentially doing basic prep, making sure we have the navigation mesh agent in place as well as checking whether the list of patrol points is actually big enough to do the job. After all, if we don’t have at least two waypoints, then we can’t conduct even the most basic of patrols. So we need to check that before we get started. If everything is ok, then we go ahead and set our first destination.
The SetDestination() method much like the previous example back in part 1. Except now, instead of just having a fixed and solitary point to pull from, we’re checking the list of patrol points for our the waypoint we’re referencing using _currentPatrolIndex. We retrieve that waypoint from the list, takes the transform from it and then set that as the target vector destination for the navmesh.
Finally, the Update() method is once again paying attention to whether we’re close to that destination. If we get close enough and the _waiting boolean is active, then the agent will wait at the current location for the allotted time (see the _totalWaitTime variable). If they don’t wait, or the wait has finished, then it will set the next patrol point by calling ChangePatrolPoint() and then update the destination. ChangePatrolPoint() will continue to increment or decrement _currentPatrolIndex and loop around the size of the collection accordingly, but it will also switch the direction depending on whether the probability _switchProbability is exceeded. This means that it will change direction, but it only does so once it has reached a patrol point and is deciding on where to go next.
In order for the final agent to run, you need to create a collection of GameObjects with the Waypoint class attached. Then gather them up and add them to the _patrolPoints field that is visible in the inspector of your NPC that has the NPCSimplePatrol class attached to it.
So in this third tutorial we’ve learned how to create at least a basic pattern of movement between a set of pre-determined points. Now this is actually rather sub-optimal for a number of reasons. Namely, that we could aim to pull these locations out of the navmesh, there is always the chance that the patrol point we have placed can’t be found on the navmesh, but also that it only follows the list in the specific order I entered it into the classes serialized field. As such, I will expand on this example in the next tutorial to create something that is a little more flexible.