Navigation

AI navigation enables non-player characters (NPCs) to move intelligently and interact with the game world. This involves creating systems that allow NPCs to traverse complex environments, avoid obstacles, and reach their goals in a realistic and efficient manner.

Core concepts

Pathfinding: Pathfinding is the process of determining the optimal path for an NPC from its current position to a target destination. This involves algorithms such as A* (A-star), Dijkstra's, and others, which calculate the shortest or most efficient route while considering various factors like terrain, obstacles, and NPC capabilities.

Navigation Meshes (Navmeshes): A navigation mesh (navmesh) is a simplified representation of the game environment used for pathfinding. It divides the walkable areas of the game world into a network of interconnected polygons. Navmeshes allow NPCs to navigate complex environments efficiently by providing a clear map of traversable areas and the connections between them.

Generating a Navmesh

To generate a Navmesh in your scene that adapts to the terrain and obstacles, you can simply ad the NavMesh actor to the scene. In the asset browser, filter on Actors and select NavMesh. Add it anywhere in the scene and it will generate a navmesh that can be used by the navigation service.

Using navigation in gameplay

When there is a Navmesh actor in the scene, the Navigation service can utilise it to calculate an optimal path between two points or find the nearest point on the Navmesh around a point.

In the example below, we create a simple actor that will find the path to the player actor and move itself toward the player by a configured movement speed every frame.


@Actor()
class AiCharacter extends BaseActor {

  private mesh = attach(MeshComponent, {
    object: new Mesh(
      new BoxGeometry(.5, .5, .5),
      new MeshStandardMaterial({color: 0xff0000})
    )
  })

  private navigation = inject(Navigation)
  private world = inject(World)

  private movementSpeed = .5

  onUpdate(deltaTime: number): void {
    const player = this.world.findActorByType(Character)

    const { success, path } = this.navigation.findPath(this.position, player.position)
    if (success) {
      const direction = path[1].clone().sub(this.position).normalize()
      this.position.addScaledVector(direction, deltaTime * this.movementSpeed)
    }
  }

}

Last updated