Giriş
Godot 4, NavigationServer2D/3D, NavigationRegion düğümleri ve NavigationAgent düğümleri üzerine inşa edilmiş sağlam bir navigasyon sistemine sahiptir. Bu, Godot 3'ün sistemine göre önemli bir gelişmedir — daha esnek, daha yüksek performanslı ve dinamik engeller ile birden fazla agent türü gibi karmaşık senaryolar için yapılandırması çok daha kolaydır.
Hızlı genel bakış: NavigationRegion, agentların nereye yürüyebileceğini tanımlar. NavigationAgent, tekil varlıklar için yol bulmayı yönetir. NavigationServer ise her şeyi arka planda yönetir.
Temel Kavramlar
- NavigationRegion2D / NavigationRegion3D — Bir NavigationPolygon (2D) veya NavigationMesh (3D) kullanarak yürünebilir bir alan tanımlar. Birden fazla bölgeye sahip olabilirsiniz; sunucu bunları otomatik olarak birleştirir.
- NavigationAgent2D / NavigationAgent3D — Yol bulmayı yönetmek için bir CharacterBody'ye eklenir. Bir sonraki yol konumunu hesaplar, kaçınmayı yönetir ve navigasyon tamamlandığında sinyaller yayar.
- NavigationServer2D / NavigationServer3D — Tüm navigasyon verilerini yöneten singleton. Onunla doğrudan nadiren etkileşime girersiniz, ancak harita güncellemelerini, yol sorgularını ve bölge bağlantılarını yönetir.
2D Navigasyon Kurulumu
Adım 1: NavigationRegion2D Ekleyin
- Sahnenize bir NavigationRegion2D düğümü ekleyin.
- Inspector'da yeni bir NavigationPolygon kaynağı oluşturun.
- 2D düzenleyicide yürünebilir poligonu çizin. Poligon, agentların nereye yürüyebileceğini tanımlar.
TileMap entegrasyonu: Bir NavigationPolygon, TileMap verilerinden bake edilebilir. Döşemelerinizde TileSet içinde tanımlanmış navigasyon poligonları varsa, yalnızca bir NavigationRegion2D ekleyip bake edin — yürünebilir alanı döşeme düzeninizden otomatik olarak oluşturur.
Bir NavigationAgent2D Eklemek
CharacterBody2D'nizin bir alt düğümü olarak bir NavigationAgent2D ekleyin. İşte eksiksiz bir hareket betiği:
extends CharacterBody2D
@export var speed: float = 200.0
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D
func _ready() -> void:
# Wait for the navigation map to be ready
await get_tree().physics_frame
nav_agent.path_desired_distance = 4.0
nav_agent.target_desired_distance = 4.0
func set_target(target_pos: Vector2) -> void:
nav_agent.target_position = target_pos
func _physics_process(delta: float) -> void:
if nav_agent.is_navigation_finished():
return
var next_pos := nav_agent.get_next_path_position()
var direction := global_position.direction_to(next_pos)
velocity = direction * speed
move_and_slide()
Önemli: NavigationServer'ın senkronize olması için bir fizik karesine ihtiyacı vardır. _ready() içinde ilk hedef konumunu ayarlamadan önce her zaman await get_tree().physics_frame çalıştırın, aksi takdirde agent geçerli bir yol bulamayabilir.
Önemli NavigationAgent2D Özellikleri
-
target_position— Agentın gitmek istediği yer -
path_desired_distance— Agentın bir sonrakine ilerlemek için her yol noktasına ne kadar yakın olması gerektiği -
target_desired_distance— Navigasyonun tamamlanmış sayılması için agentın hedefe ne kadar yakın olması gerektiği -
max_speed— Kaçınma hesaplamaları için kullanılır (hareket kodunuzu sınırlamaz)
3D Navigasyon
3D navigasyon sistemi, yalnızca farklı düğüm türleriyle olmak üzere, 2D ile aynı şekilde çalışır:
NavigationRegion3D+NavigationMeshNavigationAgent3DNavigationServer3D
extends CharacterBody3D
@export var speed: float = 5.0
@onready var nav_agent: NavigationAgent3D = $NavigationAgent3D
func _ready() -> void:
await get_tree().physics_frame
nav_agent.path_desired_distance = 0.5
nav_agent.target_desired_distance = 0.5
func set_target(target_pos: Vector3) -> void:
nav_agent.target_position = target_pos
func _physics_process(delta: float) -> void:
if nav_agent.is_navigation_finished():
return
var next_pos := nav_agent.get_next_path_position()
var direction := global_position.direction_to(next_pos)
velocity = direction * speed
velocity.y -= 9.8 * delta # Apply gravity
move_and_slide()
Navigasyon Mesh'lerini Bake Etmek
3D'de, navigasyon mesh'ini genellikle elle çizmek yerine seviye geometrinizden bake edersiniz.
Bake Yapılandırması
NavigationMesh kaynağındaki önemli özellikler:
- Agent Radius — Agentların duvarlardan ne kadar uzak durduğu. Daha büyük değerler daha temkinli yollar oluşturur.
- Agent Height — Yürünebilir alanlar için minimum tavan yüksekliği.
- Agent Max Climb — Agentların çıkabileceği maksimum basamak yüksekliği (örn. merdivenler).
- Agent Max Slope — Derece cinsinden maksimum yürünebilir eğim açısı.
# Bake navigation mesh at runtime
var nav_region: NavigationRegion3D = $NavigationRegion3D
nav_region.bake_navigation_mesh()
# Wait for baking to complete
await nav_region.bake_finished
print("Navigation mesh baked!")
Navigasyon Katmanları
Navigasyon katmanları, farklı agent türleri için yürünebilir alanları ayırmanıza olanak tanır. Örneğin, kara birimleri ile uçan birimler farklı navigasyon mesh'lerine sahip olabilir.
# Set navigation layers on the agent
nav_agent.set_navigation_layer_value(1, true) # Ground layer
nav_agent.set_navigation_layer_value(2, false) # Not flying layer
# Set navigation layers on the region
nav_region.set_navigation_layer_value(1, true) # This region is for ground
nav_region.set_navigation_layer_value(2, false) # Not for flying
Tipik bir katman yapılandırması:
- Layer 1 — Kara birimleri (askerler, araçlar)
- Layer 2 — Uçan birimler (dronlar, kuşlar)
- Layer 3 — Büyük birimler (yalnızca geniş koridorlar)
Kaçınma (Avoidance)
NavigationAgent, agentların üst üste binmesini önlemek için yerleşik yerel kaçınmaya sahiptir. Kaçınma etkinleştirildiğinde, agent diğer agentlardan uzaklaşan güvenli bir hız hesaplar.
extends CharacterBody2D
@export var speed: float = 200.0
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D
func _ready() -> void:
await get_tree().physics_frame
nav_agent.avoidance_enabled = true
nav_agent.radius = 20.0
nav_agent.max_speed = speed
nav_agent.velocity_computed.connect(_on_velocity_computed)
func set_target(target_pos: Vector2) -> void:
nav_agent.target_position = target_pos
func _physics_process(delta: float) -> void:
if nav_agent.is_navigation_finished():
return
var next_pos := nav_agent.get_next_path_position()
var direction := global_position.direction_to(next_pos)
# Set the desired velocity — the agent will compute a safe one
nav_agent.velocity = direction * speed
func _on_velocity_computed(safe_velocity: Vector2) -> void:
velocity = safe_velocity
move_and_slide()
Nasıl çalışır: Hızı doğrudan kullanmak yerine, nav_agent.velocity'yi istediğiniz hıza ayarlarsınız. Ardından agent, velocity_computed sinyali aracılığıyla yakındaki agentlardan kaçınan bir safe_velocity hesaplar. Bu güvenli hızı geri çağırma (callback) içinde uygularsınız.
Dinamik Navigasyon
Kapıları, yıkılabilir duvarları veya değişen araziyi ele almak için navigasyon mesh'ini çalışma zamanında değiştirebilirsiniz:
# Enable/disable a navigation region (e.g., open/close a door)
var door_region: NavigationRegion2D = $DoorNavigationRegion
door_region.enabled = false # Block this path
door_region.enabled = true # Open this path
# Add a navigation obstacle (blocks agent paths)
var obstacle := NavigationObstacle2D.new()
obstacle.radius = 30.0
add_child(obstacle)
# Re-bake after level changes (3D)
nav_region.bake_navigation_mesh()
await nav_region.bake_finished
Performans notu: Çalışma zamanında bir 3D navigasyon mesh'ini bake etmek maliyetlidir. 3D'deki dinamik engeller için yeniden bake etmek yerine NavigationObstacle3D kullanmayı tercih edin. 2D'de NavigationRegion2D.enabled'ı düşük maliyetle açıp kapatabilirsiniz.
Yaygın Desenler
Oyuncuyu Takip Eden Düşman Yapay Zekâsı
extends CharacterBody2D
@export var speed: float = 150.0
@export var chase_range: float = 300.0
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D
var player: Node2D
func _ready() -> void:
await get_tree().physics_frame
player = get_tree().get_first_node_in_group("player")
func _physics_process(delta: float) -> void:
if not player:
return
var distance := global_position.distance_to(player.global_position)
if distance > chase_range:
return # Too far, don't chase
# Update target every frame (or throttle to every N frames)
nav_agent.target_position = player.global_position
if nav_agent.is_navigation_finished():
return
var next_pos := nav_agent.get_next_path_position()
var direction := global_position.direction_to(next_pos)
velocity = direction * speed
move_and_slide()
NPC Devriye Rotaları
extends CharacterBody2D
@export var speed: float = 100.0
@export var patrol_points: Array[Vector2] = []
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D
var current_patrol_index: int = 0
func _ready() -> void:
await get_tree().physics_frame
if patrol_points.size() > 0:
nav_agent.target_position = patrol_points[0]
func _physics_process(delta: float) -> void:
if patrol_points.size() == 0:
return
if nav_agent.is_navigation_finished():
# Move to next patrol point
current_patrol_index = (current_patrol_index + 1) % patrol_points.size()
nav_agent.target_position = patrol_points[current_patrol_index]
return
var next_pos := nav_agent.get_next_path_position()
var direction := global_position.direction_to(next_pos)
velocity = direction * speed
move_and_slide()
Tıkla-ve-Hareket Et (Top-Down)
extends CharacterBody2D
@export var speed: float = 200.0
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D
func _ready() -> void:
await get_tree().physics_frame
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed:
nav_agent.target_position = get_global_mouse_position()
func _physics_process(delta: float) -> void:
if nav_agent.is_navigation_finished():
return
var next_pos := nav_agent.get_next_path_position()
var direction := global_position.direction_to(next_pos)
velocity = direction * speed
move_and_slide()
Godot 3'ten Godot 4'e Değişiklikler
| Godot 3 | Godot 4 |
|---|---|
Navigation2D düğümü |
Kaldırıldı. NavigationRegion2D + NavigationAgent2D kullanın |
Navigation.get_simple_path() |
NavigationServer2D.map_get_path() |
| Manuel yol takibi | NavigationAgent.get_next_path_position() bunu yönetir |
| Yerleşik kaçınma yok | NavigationAgent.avoidance_enabled |
| Navigasyon katmanı yok | Harita başına 32 navigasyon katmanı |
| Engel yok | NavigationObstacle2D/3D |