परिचय
Godot 4 में एक मज़बूत navigation सिस्टम है जो NavigationServer2D/3D, NavigationRegion नोड्स और NavigationAgent नोड्स पर आधारित है। यह Godot 3 के सिस्टम की तुलना में एक बड़ा सुधार है — अधिक लचीला, अधिक परफ़ॉर्मेंट, और डायनामिक बाधाओं तथा कई एजेंट प्रकारों जैसी जटिल स्थितियों के लिए कॉन्फ़िगर करना कहीं अधिक आसान।
त्वरित अवलोकन: NavigationRegion यह परिभाषित करता है कि एजेंट कहाँ चल सकते हैं। NavigationAgent अलग-अलग एंटिटी के लिए pathfinding संभालता है। NavigationServer पर्दे के पीछे सब कुछ प्रबंधित करता है।
मूल अवधारणाएँ
- NavigationRegion2D / NavigationRegion3D — NavigationPolygon (2D) या NavigationMesh (3D) का उपयोग करके एक चलने-योग्य क्षेत्र परिभाषित करता है। आपके पास कई रीजन हो सकते हैं; सर्वर उन्हें अपने आप जोड़ देता है।
- NavigationAgent2D / NavigationAgent3D — pathfinding संभालने के लिए इसे किसी CharacterBody से जोड़ें। यह अगली पथ स्थिति की गणना करता है, avoidance संभालता है, और navigation पूरी होने पर सिग्नल भेजता है।
- NavigationServer2D / NavigationServer3D — सिंगलटन जो सभी navigation डेटा का प्रबंधन करता है। आप शायद ही कभी इससे सीधे इंटरैक्ट करते हैं, लेकिन यह मैप अपडेट, पथ क्वेरी और रीजन कनेक्शन संभालता है।
2D Navigation सेटअप
चरण 1: NavigationRegion2D जोड़ें
- अपने सीन में एक NavigationRegion2D नोड जोड़ें।
- Inspector में एक नया NavigationPolygon रिसोर्स बनाएं।
- 2D एडिटर में चलने-योग्य पॉलीगन बनाएं। यह पॉलीगन परिभाषित करता है कि एजेंट कहाँ चल सकते हैं।
TileMap एकीकरण: NavigationPolygon को TileMap डेटा से बेक किया जा सकता है। यदि आपकी टाइल्स में TileSet के भीतर navigation पॉलीगन परिभाषित हैं, तो बस एक NavigationRegion2D जोड़ें और बेक करें — यह आपके टाइल लेआउट से चलने-योग्य क्षेत्र अपने आप जनरेट कर देगा।
NavigationAgent2D जोड़ना
अपने CharacterBody2D के चाइल्ड के रूप में एक NavigationAgent2D जोड़ें। यहाँ एक संपूर्ण मूवमेंट स्क्रिप्ट है:
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()
महत्वपूर्ण: NavigationServer को सिंक्रोनाइज़ होने के लिए एक physics frame चाहिए। _ready() में पहली टारगेट स्थिति सेट करने से पहले हमेशा await get_tree().physics_frame चलाएं, अन्यथा एजेंट को शायद कोई वैध पथ न मिले।
प्रमुख NavigationAgent2D प्रॉपर्टीज़
-
target_position— एजेंट कहाँ जाना चाहता है -
path_desired_distance— अगले पथ बिंदु पर बढ़ने के लिए एजेंट को प्रत्येक पथ बिंदु के कितने पास होना चाहिए -
target_desired_distance— navigation को पूर्ण मानने के लिए एजेंट को टारगेट के कितने पास होना चाहिए -
max_speed— avoidance गणनाओं के लिए उपयोग होता है (यह आपके मूवमेंट कोड को सीमित नहीं करता)
3D Navigation
3D navigation सिस्टम 2D के समान ही काम करता है, बस नोड प्रकार अलग होते हैं:
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()
Navigation Meshes बेक करना
3D में, आप navigation mesh को आमतौर पर हाथ से बनाने के बजाय अपनी लेवल ज्यामिति से बेक करते हैं।
बेकिंग कॉन्फ़िगरेशन
NavigationMesh रिसोर्स में प्रमुख प्रॉपर्टीज़:
- Agent Radius — एजेंट दीवारों से कितनी दूर रहते हैं। बड़े मान अधिक रूढ़िवादी पथ बनाते हैं।
- Agent Height — चलने-योग्य क्षेत्रों के लिए न्यूनतम छत की ऊँचाई।
- Agent Max Climb — अधिकतम सीढ़ी ऊँचाई जिस पर एजेंट चढ़ सकते हैं (जैसे, सीढ़ियाँ)।
- Agent Max Slope — डिग्री में अधिकतम चलने-योग्य ढलान कोण।
# 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!")
Navigation Layers
Navigation layers के साथ आप विभिन्न एजेंट प्रकारों के लिए चलने-योग्य क्षेत्रों को अलग कर सकते हैं। उदाहरण के लिए, ज़मीनी इकाइयाँ और उड़ने वाली इकाइयाँ अलग-अलग navigation mesh रख सकती हैं।
# 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
एक सामान्य लेयर सेटअप:
- Layer 1 — ज़मीनी इकाइयाँ (सैनिक, वाहन)
- Layer 2 — उड़ने वाली इकाइयाँ (ड्रोन, पक्षी)
- Layer 3 — बड़ी इकाइयाँ (केवल चौड़े गलियारे)
Avoidance (टकराव से बचाव)
NavigationAgent में एजेंटों को एक-दूसरे पर ओवरलैप होने से रोकने के लिए अंतर्निहित लोकल avoidance है। जब avoidance सक्षम होता है, तो एजेंट एक सुरक्षित वेग की गणना करता है जो अन्य एजेंटों से दूर मोड़ता है।
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()
यह कैसे काम करता है: वेग को सीधे उपयोग करने के बजाय, आप nav_agent.velocity को अपने वांछित वेग पर सेट करते हैं। फिर एजेंट velocity_computed सिग्नल के माध्यम से एक safe_velocity की गणना करता है जो पास के एजेंटों से बचता है। आप इस सुरक्षित वेग को कॉलबैक में लागू करते हैं।
डायनामिक Navigation
दरवाज़ों, तोड़ी-जा-सकने वाली दीवारों, या बदलते इलाके को संभालने के लिए आप रनटाइम पर navigation mesh को बदल सकते हैं:
# 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
परफ़ॉर्मेंस टिप: रनटाइम पर 3D navigation mesh बेक करना महंगा है। 3D में डायनामिक बाधाओं के लिए फिर से बेक करने के बजाय NavigationObstacle3D का उपयोग करना बेहतर है। 2D में आप NavigationRegion2D.enabled को कम लागत में टॉगल कर सकते हैं।
सामान्य पैटर्न
खिलाड़ी का पीछा करने वाला दुश्मन AI
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 गश्ती मार्ग
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()
क्लिक-टू-मूव (टॉप-डाउन)
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 से Godot 4 में बदलाव
| Godot 3 | Godot 4 |
|---|---|
Navigation2D नोड |
हटा दिया गया। NavigationRegion2D + NavigationAgent2D का उपयोग करें |
Navigation.get_simple_path() |
NavigationServer2D.map_get_path() |
| मैनुअल पथ अनुसरण | NavigationAgent.get_next_path_position() इसे संभालता है |
| कोई अंतर्निहित avoidance नहीं | NavigationAgent.avoidance_enabled |
| कोई navigation layers नहीं | प्रति मैप 32 navigation layers |
| कोई बाधाएँ नहीं | NavigationObstacle2D/3D |