How to Make a Basic Patrolling System for Monsters and NPCs using waypoints in Unity
Published
- Last modified
When playing games, NPCs and monsters are often found moving between one point to the other, which gives a much livelier look to a scene compared to having only static elements. In a previous article, I created a patrolling ennemy using raycasting but this time we’ll be implementing this feature by specifying a travel path, thanks to nodes in a linked list.
What is a waypoint
A waypoint is an intermediary point or place in the middle of a route. Let’s say we want our character to patrol from point A to point B, we can define intermediary points C, D, E… to be visited or passed through by the character. This is a cheap way to fit a character’s movement pattern to an environment.
Create a patrolling path using Waypoint Nodes and Linked Lists
We’ll start by creating Waypoints, a MonoBehaviour class that specifies a point which the character must reach in its patrol. This is pretty straightforward, but the trick is that we’ll be implementing a linked list as well: this means that each Waypoint will contain a reference to the next Waypoint to be reached.
The benefits of this approach are obvious: once a character has reached the waypoint (or a close enough distance), it can get the location of the next waypoint and go towards it. A patrolling system means then to go from one waypoint to the next.
Here’s how we can write it, with some convenience methods added:
publicclassWaypoint : MonoBehaviour{publicWaypoint mNextWaypoint;privateVector3 _mPosition;// Start is called before the first frame updatevoidStart() {// caching the Waypoint's position to avoid accessing the transform everytime _mPosition = transform.position; }// convenience method to quickly get distance between waypoint and characterpublicfloatGetDistance(Vector3characterPosition) {return Vector3.Distance(_mPosition, characterPosition); }// get the direction from the character to waypoint to handle character movementpublicVector3GetDirection(Vector3characterPosition) {Vector3 heading = _mPosition - characterPosition;return heading / heading.magnitude; }publicWaypointGetNextWaypoint() {return mNextWaypoint; }publicVector3GetPosition() {return _mPosition; }}
Now we’ll write our Patrolling System. This system is simple: it will move the character’s position towards the current target waypoint at a given speed. Once the distance to the waypoint is below the selected threshold, we get the reference to the next waypoint and start navigating towards it.
publicclassPatrollingSystem : BaseSystem{publicWaypoint mCurrentTargetWaypoint;publicfloat mSpeed =3f;publicfloat mDistanceThreshold =0.2f;voidUpdate() {// check distance to waypoint compared to thresholdif (mCurrentTargetWaypoint.GetDistance(transform.position) <= mDistanceThreshold) {// if close enough, get next waypoint mCurrentTargetWaypoint = mCurrentTargetWaypoint.GetNextWaypoint(); }// move towards waypoint transform.Translate( mCurrentTargetWaypoint.GetDirection() * mSpeed * Time.deltaTime ); }
This is all that’s needed! Now if we set up a character with the PatrollingSystem component, create a few gameobjects with Waypoints and link them up, we can see our navigation is working properly. Congrats!
Potential Issues and Improvements
I wanted to keep this article light, so I’ll quickly mention potential issues and how to solve them.
Our code does not include rotation
This can easily be fixed by calling transform.LookAt or use a Coroutine for a smooth rotation.
Movement logic should be changed
Avoid using translate directly on the transform. You might prefer using a CharacterController to handle your movement, and put the handling of the movement in FixedUpdate.
Adding pauses/breaks in the movement
This is pretty simple, you can add some sort of “paused” boolean property to temporarily stop the movement of the character and/or execute alternative behaviour and resume after some time or once a condition has been met.
Waypoints chain must loop
Else, the code will crash upon reaching the last node (trying to use null in mathematical operations). You must ensure no node is left without a next node. Alternatively, you can also modify the code to create a doubly linked list (keep track of parent and child) so that you can navigate the chain back up, or even set up branching paths.
That’s all for now! I hope this article will help you create your own AI systems and I hope to be able to show you a quick demonstration video on our brand new Youtube channel!