【Godot】Smart Obstacle Avoidance with NavigationRegion2D and Navigation Meshes

Created: 2025-12-08Last updated: 2025-12-16

Learn how NavigationRegion2D and navigation meshes work in Godot Engine, and how to build systems where AI smoothly navigates around obstacles—from bake settings to RVO avoidance.

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:

PropertyDescriptionRecommended Value Hints
navigation_polygonNavigationPolygon resource holding the navigation mesh data.Create new with "New NavigationPolygon".
enabledWhen true, this region is enabled on the navigation server.true by default.
source_geometry_modeHow 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:

PropertyDescriptionRecommended Value Hints
agent_radiusRadius 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:

  1. Pathfinding: Provides the next movement point via get_next_path_position(), allowing characters to avoid static obstacles.
  2. RVO Avoidance: Using the velocity_computed signal, 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 MistakeBest 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.

ElementRoleAvoids
NavigationRegion2DDefine and hold navigable areas (navigation mesh)Static walls and terrain
NavigationAgent2DExecute pathfinding and adjust movementOther 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.