Introduction: Why Game AI Needs Pathfinding
In game development, enemy character and NPC movement is an element that greatly influences the quality of player experience. When walls, obstacles, and intricate maps exist, AI needs to find the optimal path to its destination. This technology of "finding the optimal path" is pathfinding.
Godot Engine provides the NavigationAgent2D node to achieve this complex pathfinding processing simply and efficiently.
Key Concepts and NavigationAgent2D's Role
Godot's navigation system consists primarily of three elements:
| Element | Node Name | Role |
|---|---|---|
| Navigation Map | NavigationServer2D | Server managing the entire movable area. |
| Movable Area | NavigationRegion2D | Defines the area on the map where AI can actually move. |
| Path Agent | NavigationAgent2D | Requests path calculation and controls parent node (AI character) movement. |
Basic Setup
To make NavigationAgent2D work, you first need to define movable areas on the map.
- Place
NavigationRegion2D: Add aNavigationRegion2Dnode to the scene tree. - Create
NavigationPolygon: In theNavigationRegion2Dinspector, create a newNavigationPolygonresource and edit it to cover the movable parts of the map. - Prepare AI Character: Add a
NavigationAgent2Dnode as a child of the enemy AI's root node (e.g.,CharacterBody2D).
Practical Example 1: Player Tracking by Enemy AI
Enemy AI tracking the player is the most basic use case of pathfinding.
Tracking Logic Implementation
# Enemy.gd (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 set_target(new_target_position: Vector2):
target_position = new_target_position
navigation_agent.target_position = target_position
func _physics_process(delta):
if navigation_agent.is_navigation_finished():
velocity = Vector2.ZERO
move_and_slide()
return
var next_path_position = navigation_agent.get_next_path_position()
var direction = global_position.direction_to(next_path_position)
velocity = direction * speed
move_and_slide()
In this code, when you set a target with set_target(), NavigationAgent2D automatically calculates the path. In _physics_process, simply moving the character toward the position obtained from get_next_path_position() achieves movement that avoids obstacles.
Practical Example 2: Implementing Natural Patrol
Patrol behavior where enemy AI sequentially visits multiple points can also be easily implemented using NavigationAgent2D.
Patrol Logic Implementation
# PatrolEnemy.gd (attached to CharacterBody2D)
extends CharacterBody2D
@export var speed = 150.0
@onready var navigation_agent = $NavigationAgent2D
var patrol_points = [Vector2(100, 100), Vector2(500, 100), Vector2(500, 500), Vector2(100, 500)]
var current_point_index = 0
func _ready():
navigation_agent.max_speed = speed
_set_next_patrol_point()
func _set_next_patrol_point():
var next_point = patrol_points[current_point_index]
navigation_agent.target_position = next_point
func _physics_process(delta):
if navigation_agent.is_navigation_finished():
current_point_index = (current_point_index + 1) % patrol_points.size()
_set_next_patrol_point()
var next_path_position = navigation_agent.get_next_path_position()
var direction = global_position.direction_to(next_path_position)
velocity = direction * speed
move_and_slide()
The key to this implementation is using navigation_agent.is_navigation_finished(). This method returns true when the agent judges it has reached the target point, enabling more accurate and reliable target arrival detection than manually calculating distance.
Implementation Best Practices
1. Controlling Path Recalculation Frequency
Every time you set navigation_agent.target_position, path recalculation occurs. For player-tracking AI, updating the target every frame could impact performance.
- Using Timers: Use a timer node to update target position at fixed intervals like every 0.1 seconds.
- Distance-Based Detection: Update target position only when the player moves beyond a certain distance.
2. Pursuing Smooth Movement
NavigationAgent2D tells you the next point on the path, but it's the developer's responsibility to move the character toward that point.
Rather than just moving toward the next point, gradually changing `velocity** creates smoother movement.
3. Utilizing get_next_path_position()
NavigationAgent2D calculates the complete path to the target point, but what the character should move toward is the next point on that path. get_next_path_position() returns the next point on the path closest to the character's current position.
Summary
Godot Engine's NavigationAgent2D is a powerful tool that dramatically simplifies AI movement logic in 2D games.
- Define movable areas with NavigationRegion2D,
- Set target position in NavigationAgent2D,
- Move the character toward the next point obtained from get_next_path_position()
With this simple procedure, you can immediately integrate practical and natural AI into your game that smartly avoids obstacles, tracks players, or patrols designated routes.