Recast graph in a 3D game

Example scene which demonstrates a recast graph in a 3D level.

This example scene demonstrates how to use a recast graph in a 3D game. It also demonstrates how to use the Interactable component to create simple interactive objects, and it contains an example of an off-mesh link, and how to use the NavmeshCut component to create dynamic obstacles on recast graphs.

There's a single agent in the scene that you can move around by clicking on the ground. You can also press "P" to spawn a dynamic obstacle in the form of a small box that falls down on the ground.

Contents

Graph setup

The graph used in this scene is a RecastGraph. A recast graph has been chosen because:

  • It supports the overhangs and bridges that are present in this scene.

  • It can easily represent the required level of detail.

  • It easily supports the dynamic obstacles that are present in this scene, with good precision.

A layered grid graph could also have been used for this scene. But it would likely have required a higher level of detail to represent the dynamic obstacles well. This scene does not benefit from the layered grid graph's better support for granular tags and penalties, and the world is itself not grid-based, so a recast graph is a better fit.

Chests

This example scene contains a few chests which can be opened by the player by clicking on them.

These chests use the Interactable component to implement a simple state machine which controls the animation of the chest and movement of the character.

Note

The Interactable component is a very simple state machine implementation which is intended for the example scenes. In a real game, you would probably want to use a more advanced state machine implementation, but this script can serve as a good example if you want to write your own state machine code for your game.

The TargetMover component on the main camera contains code which detects if the player clicks on an interactable object and if so, it will start the interaction. In this case, the interactable is configured to perform the following steps:

  1. Spawn the same "move here" particle effect as when the player normally clicks somewhere on the ground.

  2. Make the agent move to the chest, and rotate to face it.

  3. Play the chest opening animation and spawn some particle effects.

In one corner of the map there's a ledge which the agent can jump down from. This is implemented using a NodeLink2 component.

Off-mesh links connect two parts of the navmesh that are not normally connected. They are used for things like jumping down from ledges, climbing ladders, opening doors, etc.

This off-mesh link is configured with a start point at the top of the ledge, and the end point at the bottom of the ledge. The link is also configured to be one-way, to prevent the agent from trying to jump up the ledge. A cost factor of 2 has been used to make the agent prefer to walk around the ledge instead of jumping down from it. A cost factor of 1 would mean that the link is equally expensive as moving the same distance on the normal navmesh.

Navmesh cutting

When in game mode, you can press "P" to create a dynamic obstacle in the form of a small box that falls down on the ground. It affects the navmesh using the NavmeshCut component.

Navmesh cutting is pretty fast on recast/navmesh graphs compared to recalculating tiles from scratch. But it is a bit more limited, since it can only be used to remove parts of the navmesh, not add new parts. The resulting navmesh is also not quite as good as if it had been recalculated from scratch. But for most games, navmesh cutting is great for dynamic obstacles.

The navmesh cut on the box is configured as a sphere with a radius that approximates the cube. With a resolution of 6, the navmesh cut will remove a hexagonal shape from the navmesh. It could equally well have been configured using the "Box" shape, but the sphere shape is slightly simpler, and the rounded shape leads to nicer movement around the box.

Character animation

The character animation is handled by the MineBotAnimation script.

This script will forward the movement speed to the animator component using the following animator parameter:

  • NormalizedSpeed: Movement speed in world units, divided by MineBotAnimation.naturalSpeed and the character's scale. This will be 1 when the agent is moving at the natural speed, and 0 when it is standing still.

In the animator controller, the root has two states: forward and idle. These are two animation clips that are transitioned between, depending on if the NormalizedSpeed is high enough. The forward animation clip is also configured to multiply its speed by the NormalizedSpeed parameter, so that the animation will play faster or slower depending on how fast the agent is moving.