Thursday, February 18, 2016

Unity waypoint system with NavMesh

Unity version: 5.3
Mode: 3D 
Level: Beginner

I wanted to create a patrolling NPC for my game so that requires a waypoint system. It is fairly easy to do with the NavMeshAgent.

First let's create our test scene and add a couple of empty GameObjects.

Create a GameObject as a container, name it WaypointsForNPC, or whatever is your character's name, just so you know who they belong to. Make sure the location is at zero.


Create a child GameObject and name it Waypoint, you should add an icon to it so you can see the location in the editor. I have provided a simple 'flag' icon you can import as an asset. You can then just make it a prefab and make copies, name them accordingly.




Place the waypoints on the map, on terrain or plane (as long as it's static and generally walkable)



Next, create the NPC. Here we just use a sphere object. Add NavMeshAgent to it.


Next, use the Navigation tab and hit Bake in the bottom. This will bake the navigation mesh for you and it should show the walkable area in the scene view.

Now let's start coding. Select your NPC and add a new script. Let's call it NPCWalkToWaypoint. Open up the script and add these lines before the Start() -method:

    public Transform[] waypoints;
    public bool loop = false;

    private NavMeshAgent agent;
    private int waypointCount, waypointIteration;


First is an array of Transforms. These are your waypoints. Next is a boolean value, determining if we should loop the walking, meaning the NPC will walk forever between the waypoints. NavMeshAgent is the component you use to move the NPC and the two integers are used to control what waypoints to use.

Now let's initialize those values in Start() -method:

    agent = GetComponent<NavMeshAgent> ();
    agent.SetDestination (waypoints [0].position);

    waypointCount = waypoints.Length;
    waypointIteration = 0;


Alright, first we fetch the NavMeshAgent component from the NPC this script is attached to, then we set its destination to the first waypoint in the array. Notice we don't do any checks if the array is empty, for simplicity's sake we just assume it has something.

Onwards to Update() method:


    if (agent.hasPath) {
        if (agent.remainingDistance < .5f) {
            if (waypointIteration < waypointCount) { 

               agent.SetDestination (
                   waypoints [waypointIteration].position);
                   waypointIteration++;
            } else {
                if (loop) {
                    waypointIteration = 0;

                }
            }
    }



First we check if the agent has any path calculate currently (meaning its destination is set). Then we check if we reached the destination. You can play with the value here but for my purposes I found 0.5 works well. If yes then we check if we have any more waypoints to travel to. If no more is found, just set the iteration to 0 and the next update will send the NPC to the first waypoint.


Head back to the editor and drag the waypoints to the array on the component.



Hit play and witness your patrolling NPC.



Whole script:

using UnityEngine;
using System.Collections;

public class NPCWalkToWaypoint : MonoBehaviour
{

    public Transform[] waypoints;
    public bool loop = false;

    private NavMeshAgent agent;
    private int waypointCount, waypointIteration;

    void Start ()
    {
        agent = GetComponent<NavMeshAgent> ();
        agent.SetDestination (waypoints [0].position);

        waypointCount = waypoints.Length;
        waypointIteration = 0;
    }

    void Update ()
    {
        if (agent.hasPath) {
            if (agent.remainingDistance < .5f) {
                if (waypointIteration < waypointCount) {
                    agent.SetDestination (waypoints [waypointIteration].position);
                    waypointIteration++;
                } else {
                    if (loop) {
                        waypointIteration = 0;
                    }
                }
            }
        }
    }
}