In game development, "smart AI movement" where NPCs navigate to destinations while avoiding obstacles greatly enhances player experience. In Godot Engine, NavigationRegion2D nodes and navigation meshes handle this pathfinding and obstacle avoidance.
This article explains the roles of these nodes and how to use them to create systems where characters smoothly navigate around obstacles, with concrete code examples.
Why Navigation Meshes Are Necessary
Navigation meshes are necessary for character movement because traditional physics-based movement doesn't let characters know obstacles exist until they collide with them.
- Physics-based Movement (Collision-based): Characters only recognize obstacles when they actually collide with them (
StaticBody2D, etc.). This is like "hitting a dead end then looking for another path"—inefficient and unnatural. - Navigation Mesh (Path-based): "Navigable areas" are pre-defined as polygon meshes. AI references this map and calculates optimal paths that avoid obstacles before colliding.
NavigationRegion2D manages this "map for AI" and places it in scene space.
Generating (Baking) Navigation Meshes with NavigationRegion2D
The process of generating navigation meshes is called "baking." In Godot, navigable areas can be automatically calculated based on shapes of collision-enabled nodes placed in the scene.
Scene Preparation
First, construct your stage with nodes that have CollisionShape2D or CollisionPolygon2D, such as TileMap or StaticBody2D. These become "obstacles" for the navigation mesh.
NavigationRegion2D Setup
Add a NavigationRegion2D node to the scene and configure the following key properties in the inspector:
| Property | Description | Recommended Value Hints |
|---|---|---|
navigation_polygon | NavigationPolygon resource holding the navigation mesh data. | Create new with "New NavigationPolygon". |
enabled | When true, this region is enabled on the navigation server. | true by default. |
source_geometry_mode | How to obtain geometry for mesh generation. | For TileMap, use SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN and add TileMap to a navigation group. |
Important properties to set on the NavigationPolygon resource:
| Property | Description | Recommended Value Hints |
|---|---|---|
agent_radius | Radius of the moving agent. Paths are generated keeping safe distance from walls and obstacles. | Set slightly larger than character's collision radius. |
Baking the Mesh
Once configured, select the NavigationRegion2D node and click the "Bake NavigationMesh" button in the editor's top toolbar. On success, a blue semi-transparent polygon appears in the scene view. This is the area where AI can move.
Practical Movement Script with NavigationAgent2D
Once the navigation mesh is complete, implement characters that move on it. NavigationAgent2D plays the central role here.
Add NavigationAgent2D as a child node of the character you want to move (e.g., CharacterBody2D). This agent communicates with the navigation server, calculating paths and avoiding collisions with other agents.
Extended Movement Script
The following script moves a character to the clicked mouse position.
# Script attached to CharacterBody2D
extends CharacterBody2D
@export var speed: float = 200.0
@onready var navigation_agent: NavigationAgent2D = $NavigationAgent2D
func _ready() -> void:
# Set agent properties
navigation_agent.path_desired_distance = 4.0
navigation_agent.target_desired_distance = 4.0
func _physics_process(delta: float) -> void:
if navigation_agent.is_navigation_finished():
return
# Get current target position
var current_agent_target: Vector2 = navigation_agent.get_next_path_position()
# Calculate movement direction
var new_velocity: Vector2 = (current_agent_target - global_position).normalized() * speed
# Apply RVO (Reciprocal Velocity Obstacles) collision avoidance
# Calling set_velocity() returns safe velocity via velocity_computed signal
navigation_agent.set_velocity(new_velocity)
func _input(event: InputEvent) -> void:
if event.is_action_pressed("click"):
# Set mouse click position as target
navigation_agent.target_position = get_global_mouse_position()
func _on_navigation_agent_2d_velocity_computed(safe_velocity: Vector2) -> void:
# Only call move_and_slide() in signal handler
# (avoid double calling with _physics_process)
velocity = safe_velocity
move_and_slide()
Pathfinding and RVO Avoidance
NavigationAgent2D serves two main roles:
- Pathfinding: Provides the next movement point via
get_next_path_position(), allowing characters to avoid static obstacles. - RVO Avoidance: Using the
velocity_computedsignal, obtain velocity vectors adjusted based on RVO (Reciprocal Velocity Obstacles) to avoid collisions with other moving agents.
Handling Dynamic Obstacles
To avoid obstacles that appear dynamically during gameplay (e.g., objects placed by players), add a NavigationObstacle2D node to those obstacles.
NavigationObstacle2D sets up temporary "avoidance zones" around itself without re-baking the mesh. This causes other agents with NavigationAgent2D to adjust their behavior to avoid these dynamic obstacles.
Common Mistakes and Best Practices
| Common Mistake | Best Practice |
|---|---|
Setting target_position every frame in _physics_process. | Set target_position only once when the destination changes (e.g., on mouse click). Setting it every frame causes repeated path calculations and performance degradation. |
Directly setting global_position to get_next_path_position() result. | This causes teleporting-like unnatural movement. get_next_path_position() is just "the next waypoint." Characters should move from current position toward that waypoint. |
| RVO avoidance not working (characters overlapping). | Use NavigationAgent2D's velocity_computed signal and set the calculated safe_velocity to CharacterBody2D's velocity for reliable results. |
| Dynamic obstacles not being avoided. | Check if NavigationObstacle2D is enabled and if obstacle collision layers and agent collision masks are properly configured. |
Summary
NavigationRegion2D and navigation meshes are fundamental elements for implementing smart AI movement in Godot Engine.
| Element | Role | Avoids |
|---|---|---|
NavigationRegion2D | Define and hold navigable areas (navigation mesh) | Static walls and terrain |
NavigationAgent2D | Execute pathfinding and adjust movement | Other moving agents, NavigationObstacle2D |
By understanding and utilizing this system, your game's NPCs can understand map structure, coordinate with other characters, and smartly reach their destinations.