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.

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:
public class Waypoint : MonoBehaviour
{
public Waypoint mNextWaypoint;
private Vector3 _mPosition;
// Start is called before the first frame update
void Start()
{
// caching the Waypoint's position to avoid accessing the transform everytime
_mPosition = transform.position;
}
// convenience method to quickly get distance between waypoint and character
public float GetDistance(Vector3 characterPosition)
{
return Vector3.Distance(_mPosition, characterPosition);
}
// get the direction from the character to waypoint to handle character movement
public Vector3 GetDirection(Vector3 characterPosition)
{
Vector3 heading = _mPosition - characterPosition;
return heading / heading.magnitude;
}
public Waypoint GetNextWaypoint()
{
return mNextWaypoint;
}
public Vector3 GetPosition()
{
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.
public class PatrollingSystem : BaseSystem
{
public Waypoint mCurrentTargetWaypoint;
public float mSpeed = 3f;
public float mDistanceThreshold = 0.2f;
void Update() {
// check distance to waypoint compared to threshold
if (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.
1- Our code does not include rotation
This can easily be fixed by calling transform.LookAt or use a Coroutine for a smooth rotation.
2- 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.
3- 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.
4- 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!