In game development, "smart AI movement" where NPCs avoid obstacles in the map while moving to their destination greatly enhances player experience. In Godot Engine, the NavigationRegion2D node and navigation mesh handle this pathfinding and obstacle avoidance.
This article explains the roles of these nodes and the mechanism by which characters smoothly move while avoiding obstacles, with concrete code examples.
Why Navigation Mesh Is Necessary
The reason a navigation mesh is necessary for character movement is that with traditional physics-based movement, characters cannot know about obstacles until they collide with them.
A navigation mesh is a data structure defining areas where agents can safely move. While physics collision defines "impassable places," navigation mesh clearly defines "passable places." This allows Godot's navigation system to calculate the optimal path before collision.
NavigationRegion2D's Role and Mesh Generation
The NavigationRegion2D node holds navigation mesh data (NavigationMesh resource) and defines where to place that mesh in the scene.
Mesh Baking (Generation)
The process of generating a navigation mesh is called "baking." The most common method is automatically generating the mesh based on collision information in the scene.
In the NavigationRegion2D inspector, configure the following key properties:
| Property Name | Description |
|---|---|
agent_radius | The radius of the moving agent. A "passable area" is calculated at a safe distance from walls and obstacles. |
source_geometry_mode | Specifies how to obtain source geometry (collision) for mesh generation. |
After these settings, select the NavigationRegion2D node and execute "Bake Navigation Mesh" from the top menu to generate the navigation mesh.
Practice! Implementing Movement That Avoids Obstacles
To move characters on the navigation mesh, use the NavigationAgent2D node. Add this as a child of the moving character and perform pathfinding and movement adjustment.
Script Implementation
# Script attached to CharacterBody2D
extends CharacterBody2D
@export var speed = 200.0
@onready var navigation_agent = $NavigationAgent2D
var target_position = Vector2.ZERO
func _ready():
navigation_agent.max_speed = speed
func _physics_process(delta):
if target_position != Vector2.ZERO:
navigation_agent.target_position = target_position
var next_location = navigation_agent.get_next_path_position()
var new_velocity = (next_location - global_position).normalized() * speed
velocity = navigation_agent.get_next_velocity()
move_and_slide()
func set_target(new_target: Vector2):
target_position = new_target
Pathfinding and RVO Avoidance
NavigationAgent2D fulfills two main roles:
- Pathfinding: Provides the next movement point through
get_next_path_position(), allowing characters to avoid static obstacles (areas outside the mesh). - RVO Avoidance:
get_next_velocity()returns a velocity vector adjusted based on RVO (Reciprocal Velocity Obstacles) to avoid collisions with other moving agents. This achieves cooperative movement where characters don't collide with other NPCs.
Handling Dynamic Obstacles
To make AI avoid obstacles that appear dynamically during the game (e.g., objects placed by the player), add a NavigationObstacle2D node to those obstacles.
NavigationObstacle2D sets a temporary "avoidance area" around itself without rebaking the mesh. This makes other agents with NavigationAgent2D adjust their behavior to avoid this dynamic obstacle.
Summary
NavigationRegion2D and navigation mesh are fundamental elements for achieving smart AI movement in Godot Engine.
| Element | Role | What It Avoids |
|---|---|---|
NavigationRegion2D | Defines and holds movable areas (navigation mesh) | Static walls and terrain |
NavigationAgent2D | Executes pathfinding and adjusts movement | Other moving agents, NavigationObstacle2D |
By understanding and utilizing this system, the NPCs in your game will be able to understand map structure, cooperate with other characters, and smartly reach their destinations.