Navigation with the Nav Mesh Part 5: Areas and Paths

In this final part, we will improve our project by adding areas to the Nav Mesh with some different rules, and also use the CalculatePath() method to make the enemy check their path before deciding to follow it or not.

Area Types

We will now create a new terrain so that we can treat areas of the scene differently.

We will give the platform we created earlier its own area type distinct from the rest of the Nav Mesh.

  1. Open the Navigation window.
  2. Select the Areas tab.
  3. Create a new area type called ‘Player Only’, as in the image below:

clip_image001

  1. Select the Object tab.
  2. Select the Platform GameObject in the Hierarchy.
  3. Change the Navigation Area (in the Navigation window) to Player Only.
  4. Select the Bake tab in the Navigation window.
  5. Click Bake to re-bake the Nav Mesh.

You have now added a different area type and assigned it to a piece of the Nav Mesh. Your Nav Mesh should now look like the image below, with a different colour on the platform area to show that it is a different type of area:

clip_image002

That’s a new area type created! Now let’s make it so our Enemy object cannot walk on the Player Only area:

  1. Select the Enemy GameObject in the Hierarchy.
  2. Deselect Player Only from the Area Mask drop-down list (the area types with a tick next to them are the ones this agent can walk on).

clip_image003

Now play your scene, and get your player onto the platform. If everything is working correctly, the enemy won’t be able to jump up to catch the player.

You can use this same technique for many different things. For example, you could make a passageway using a different area type, and restrict certain characters from using that passageway.

Calculate Path

The CalculatePath() method of the Nav Mesh Agent allows us to calculate a path through the Nav Mesh without actually moving along that path. This can be useful for a number of things, such as:

  • Checking if there is a valid path to a certain place
  • Storing a path to use later
  • Storing a path to re-use for multiple agents

We will change the code so that the enemy will check for a valid path before chasing the player. If no path is found (e.g. When the player is on the platform the enemy can’t walk on), the enemy will resume patrolling.

CalculatePath() calculates the path, and stores the path’s status in the path.status property. The status can be one of three values:

  • PathComplete
  • PathPartial
  • PathInvalid

We only care whether the path is complete or not for our needs.

We will have to make a few changes to the enemy script to accommodate the new behaviour, and we’ll also take the opportunity to improve the way the Chasing behaviour is coded.

Edit the Enemy Script

Open up the Enemy script:

NOTE: We will rename the SetDestination method in the Enemy script to ‘Chase()’, as this is more accurate now that we have made many changes to the project. SetDestination() was a bad name because it didn’t really describe the functionality, and is also the same as the SetDestination() function on the NavMeshAgent component.

  1. Replace the SetDestination() method with this Chase() method:
void Chase()
{
    var path = new NavMeshPath();
    agent.CalculatePath(objectToChase.position, path);
    if(path.status == NavMeshPathStatus.PathComplete)
    {
        agent.SetDestination(objectToChase.position);
        currentState = EnemyStates.Chasing;
    }
    else
    {
        currentState = EnemyStates.Patrolling;
    }
}

The new code calculates a path before chasing. If a complete path to the player is not found, the enemy reverts to the patrolling state. Because this code is a bit nicer than the previous version, we no longer need the InvokeRepeating() call, so do the following:

  1. Remove the InvokeRepeating() call fro the Start() method.
  2. Add a new variable to the script to track the time since the enemy last scanned for a path to the player:

float timeSinceScan = 0;

For this to work, a change is needed in the Update() method as well. Below is the full updated Update() method:

void Update()
{
    if (Vector3.Distance(transform.position, objectToChase.position) > 16f)
    {
        currentState = EnemyStates.Patrolling;
    }
    else
    {
        if(currentState == EnemyStates.Patrolling) Chase();
    }
    if (currentState == EnemyStates.Patrolling)
    {
        if (Vector3.Distance(transform.position, waypoints[currentWaypoint].position) <= 0.6f) 
    { 
        currentWaypoint++; 
        if (currentWaypoint == waypoints.Length) 
        { 
            currentWaypoint = 0;
        }
     } 
    agent.SetDestination(waypoints[currentWaypoint].position);
    }
          if(currentState == EnemyStates.Chasing) 
          {
             if(timeSinceScan >= decisionDelay)
             {
                  timeSinceScan = 0;
                  Chase();
             }
        }
    timeSinceScan += Time.deltaTime;
}

Now, when the player is on the platform, the enemy goes back to patrolling because it can't reach the player.

Terrain

You can also set different parts of the Nav Mesh to act like different types of terrain by making it 'cheaper' or 'more expensive' to travel over some areas. This will influence the agents as they decide how to get from one place to another. We will now create some more terrain, and make some of it faster to walk on than the main terrain, and then see how this affects navigation of our agents.

  1. Create a new quad and place it up against the existing terrain, but give it a different material so you can tell it apart from the rest of the level. Here is how mine is set up, with a red material to make the area distinct:

clip_image004

  1. In the Navigation window, select the Areas tab and add a new area called Fast Movement, then adjust the cost of the terrains to match the image below:

clip_image005

This means that the main mesh, which is in the Walkable area, has a relative 'cost' of 3, but the new Fast Movement area has a cost of only 1, making it quicker to move on, and therefore more desirable to the agents when planning a route.

The new ground section needs to be added to the Nav Mesh and set as Fast Movement. This is done in the same way we set the platform to be Player Only earlier:

  1. Select the Object tab in the Navigation window.
  2. Select the new ground section in the Hierarchy to make it the active object.
  3. Change the ground's Navigation Area to Fast Movement:

clip_image006

  1. Select the Bake tab and re-bake the Nav Mesh.

Now the level has three distinct areas (blue, pink, and brown):

clip_image007

You will now notice that the agents will find a path via the Fast Movement area even if it means not travelling in a straight line. You can use this behaviour for all kinds of things, such as rough terrain that slows the player down, or short cuts using less costly terrain.

That's All

That's everything for this series of tutorials on Unity's navigation system. If you want to dig further, Unity has some more advanced Nav Mesh tools that don't come included with Unity, but which can be downloaded separately from the link below. These tools allow more control, such as having different agent types with different sizes (for example, you could have large enemies that can't fit through smaller gaps that the player can escape into).

Unity Nav Mesh Tools
Full project download

Final Project Download

Download the completed AI project here: http://unity.grogansoft.com/downloads/AI/ai_project-Part_4.zip

Leave a Reply

Your email address will not be published.