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.

Demo Patrolling System
Our Patrolling System will give us a result similar to this

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!