Collision Layers क्यों महत्वपूर्ण हैं
Collision layers, Godot 4 में सभी physics इंटरैक्शन का आधार हैं — मूवमेंट, हिट डिटेक्शन, रेकास्टिंग, Area ट्रिगर, और बहुत कुछ। Layer और Mask के बीच अंतर को समझना महत्वपूर्ण है, और इसे गलत समझना शुरुआती के साथ-साथ अनुभवी डेवलपर्स के लिए भी सबसे आम मुश्किलों में से एक है।
Layer बनाम Mask — मानसिक मॉडल
Godot में प्रत्येक physics ऑब्जेक्ट के दो bitmask प्रॉपर्टीज़ होती हैं:
- Layer = "मैं इन layers पर मौजूद हूं" (मैं क्या हूं)
- Mask = "मैं इन layers को स्कैन करता हूं" (मैं क्या देख / टकरा सकता हूं)
मूल नियम
A, B से टकराता है जब A का Mask, B के Layer को शामिल करता है या B का Mask, A के Layer को शामिल करता है। टकराव होने के लिए केवल एक पक्ष को दूसरे को "देखना" पर्याप्त है।
Project Settings में Layers का नामकरण
कोई भी कोड लिखने से पहले, अपने layers को नाम दें। इससे Inspector का उपयोग काफी आसान हो जाता है और जैसे-जैसे आपका प्रोजेक्ट बढ़ता है, भ्रम से बचाव होता है।
Project Settings > Layer Names > 2D Physics (या 3D Physics):
| Layer सं. | नाम | उद्देश्य |
|---|---|---|
| 1 | Player | प्लेयर कैरेक्टर |
| 2 | Enemy | सभी दुश्मन बॉडीज़ |
| 3 | Environment | दीवारें, फ़र्श, प्लेटफ़ॉर्म |
| 4 | Projectile | गोलियां, तीर, स्पेल |
| 5 | Pickup | आइटम, सिक्के, हेल्थ पैक |
| 6 | Trigger | सेंसर, स्पॉन ज़ोन, चेकपॉइंट |
कोड में Layers सेट करना (GDScript)
Godot 4 दो दृष्टिकोण प्रदान करता है — वैल्यू-आधारित API (अनुशंसित) और सीधा bitmask असाइनमेंट:
# Godot 4 API — value-based (1-indexed, recommended)
set_collision_layer_value(1, true) # I am on layer 1
set_collision_mask_value(2, true) # I detect layer 2
# Or use bitmask directly
collision_layer = 1 # Layer 1 only (bit 0)
collision_mask = 6 # Layers 2 and 3 (bits 1 + 2 = 6)
# Read current state
var on_layer_1: bool = get_collision_layer_value(1)
var scans_layer_2: bool = get_collision_mask_value(2)
Bitmask का जाल
set_collision_layer_value() में Layer संख्याएं 1-आधारित होती हैं, लेकिन अंतर्निहित bitmask 0-आधारित है। Layer 1 = bit 0 = मान 1, Layer 2 = bit 1 = मान 2, Layer 3 = bit 2 = मान 4। संदेह होने पर, गलतियों से बचने के लिए वैल्यू-आधारित API का उपयोग करें।
सामान्य Layer योजनाएं
Platformer / Side-Scroller
| ऑब्जेक्ट | Layer | Mask | व्याख्या |
|---|---|---|---|
| Player | 1 | 2, 3, 5, 6 | दुश्मनों, वातावरण, पिकअप, ट्रिगर का पता लगाता है |
| Enemy | 2 | 1, 3 | प्लेयर और वातावरण का पता लगाता है |
| Environment | 3 | — | निष्क्रिय — दूसरों द्वारा पता लगाया जाता है |
| Projectile | 4 | 2, 3 | दुश्मनों और दीवारों से टकराता है |
| Pickup | 5 | — | निष्क्रिय — प्लेयर इसका पता लगाता है |
| Trigger | 6 | 1 | केवल प्लेयर का पता लगाता है |
Top-Down / Roguelike
| ऑब्जेक्ट | Layer | Mask | व्याख्या |
|---|---|---|---|
| Player | 1 | 2, 3, 5, 6 | दुश्मनों, दीवारों, NPCs, सेंसर का पता लगाता है |
| Enemy | 2 | 1, 3 | प्लेयर और दीवारों का पता लगाता है |
| Wall | 3 | — | निष्क्रिय |
| Bullet | 4 | 1, 2, 3 | प्लेयर, दुश्मनों और दीवारों से टकराता है |
| NPC | 5 | 3 | केवल दीवारों से टकराता है |
| Sensor | 6 | 1 | प्लेयर के प्रवेश का पता लगाता है |
Area2D / Area3D Layers
Areas उसी Layer/Mask सिस्टम का उपयोग करती हैं। इसके अतिरिक्त, उनके पास दो टॉगल प्रॉपर्टीज़ होती हैं:
-
monitoring— यदिtrueहै, तो यह Area उसमें प्रवेश करने वाले अन्य ऑब्जेक्ट्स का सक्रिय रूप से पता लगाती है। -
monitorable— यदिtrueहै, तो अन्य Areas इस Area का पता लगा सकती हैं।
सिग्नल: area_entered बनाम body_entered
body_entered तब ट्रिगर होता है जब कोई PhysicsBody (CharacterBody, RigidBody, StaticBody) Area में प्रवेश करता है। area_entered तब ट्रिगर होता है जब कोई अन्य Area इसमें प्रवेश करती है। सुनिश्चित करें कि आप अपने उपयोग के लिए सही सिग्नल कनेक्ट करें।
# Pickup Area2D — detect when the Player body enters
func _ready() -> void:
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"):
collect()
queue_free()
RayCast Collision Mask
RayCast नोड्स के पास केवल एक Mask होता है (कोई Layer नहीं), क्योंकि वे डिटेक्टर हैं, न कि physical बॉडीज़। रे किससे टकरा सकता है, इसे फ़िल्टर करने के लिए Mask सेट करें:
# RayCast that only detects enemies (layer 2)
$RayCast2D.collision_mask = 2 # Layer 2 = Enemy
# Or use the value-based API:
$RayCast2D.set_collision_mask_value(1, false) # Ignore Player
$RayCast2D.set_collision_mask_value(2, true) # Detect Enemy
$RayCast2D.set_collision_mask_value(3, false) # Ignore Environment
# Line-of-sight ray that ignores projectiles
$LineOfSight.collision_mask = 0
$LineOfSight.set_collision_mask_value(1, true) # Player
$LineOfSight.set_collision_mask_value(3, true) # Environment
व्यावहारिक उदाहरण: Player – Enemy – Projectile
यहां एक सामान्य एक्शन गेम के लिए एक संपूर्ण layer सेटअप है। प्रत्येक निर्णय के पीछे का तर्क कमेंट्स में दिखाया गया है:
# Player (CharacterBody2D)
# Layer: 1 (Player) — "I am the player"
# Mask: 2 (Enemy), 3 (Environment), 5 (Pickup)
# — I collide with enemies, walls, and can pick up items
# Enemy (CharacterBody2D)
# Layer: 2 (Enemy) — "I am an enemy"
# Mask: 1 (Player), 3 (Environment)
# — I collide with the player and walls
# Player Bullet (Area2D)
# Layer: 4 (Projectile) — "I am a projectile"
# Mask: 2 (Enemy), 3 (Environment)
# — I hit enemies and walls, but NOT the player who fired me
# Enemy Bullet (Area2D)
# Layer: 4 (Projectile) — "I am a projectile"
# Mask: 1 (Player), 3 (Environment)
# — I hit the player and walls, but NOT the enemy who fired me
टिप: Friendly-Fire रोकना
ध्यान दें कि Player Bullets, Layer 2 (Enemy) को मास्क करती हैं लेकिन Layer 1 (Player) को नहीं, और Enemy Bullets, Layer 1 (Player) को मास्क करती हैं लेकिन Layer 2 (Enemy) को नहीं। इस तरह आप पूरी तरह से layer कॉन्फ़िगरेशन के माध्यम से friendly-fire को रोकते हैं — बिना किसी कोड के।
डिबगिंग टिप्स
- दृश्यमान Collision Shapes: एडिटर में Debug > Visible Collision Shapes पर जाएं ताकि रनटाइम पर सभी collision shapes प्रस्तुत हों। यह तुरंत गायब या गलत संरेखित colliders को उजागर करता है।
- Inspector जांच: एक नोड चुनें और Inspector में Collision > Layer और Collision > Mask को विस्तृत करें। प्रत्येक bit पर होवर करके उसका नाम देखें (यदि आपने उन्हें Project Settings में नाम दिया है)।
-
रनटाइम पर प्रिंट करें: गेमप्ले के दौरान bitmask मानों को सत्यापित करने के लिए
print("Layer: ", collision_layer, " Mask: ", collision_mask)।
Godot 3 → 4 माइग्रेशन परिवर्तन
| Godot 3 | Godot 4 |
|---|---|
set_collision_layer_bit(bit, value) |
set_collision_layer_value(layer, value) |
set_collision_mask_bit(bit, value) |
set_collision_mask_value(layer, value) |
bit पैरामीटर 0-आधारित था
|
layer पैरामीटर 1-आधारित है
|
| 20 layers उपलब्ध | 32 layers उपलब्ध |
माइग्रेशन का जाल
यदि आप किसी Godot 3 प्रोजेक्ट को पोर्ट कर रहे हैं, तो याद रखें कि set_collision_layer_bit(0, true) अब set_collision_layer_value(1, true) बन जाता है। इंडेक्स +1 से खिसक जाता है। यदि आप इसे चूक जाते हैं, तो आपके सभी layers एक से खिसक जाएंगे।
सामान्य गलतियां
1. Mask सेट करना भूल जाना
आपके ऑब्जेक्ट के पास एक Layer है, लेकिन Mask खाली है (सभी शून्य)। ऑब्जेक्ट physics दुनिया में मौजूद है, पर किसी का पता नहीं लगाता। मेल खाते masks वाले अन्य ऑब्जेक्ट अभी भी इसका पता लगाएंगे, लेकिन इस ऑब्जेक्ट पर move_and_slide() हर चीज़ से होकर गुज़र जाएगा।
2. Layer को Mask के साथ गड़बड़ा देना
प्लेयर के Mask के बजाय उसके Layer को 2 (Enemy) पर सेट करना। अब जहां तक physics इंजन का सवाल है, प्लेयर एक दुश्मन है। हमेशा याद रखें: Layer = मैं क्या हूं, Mask = मैं क्या स्कैन करता हूं।
3. Layer संख्याओं के बजाय Bitmask मानों का उपयोग करना
यह सोचकर set_collision_layer_value(4, true) लिखना कि यह bitmask मान 4 (Layer 1+2) सेट करता है। वास्तव में, यह Layer 4 को सक्षम करता है। वैल्यू-आधारित API, layer संख्याएं लेता है, न कि bit मान।
4. जहां दोनों तरफ की अपेक्षा हो, वहां एकतरफ़ा पता लगना
ऑब्जेक्ट A, B के Layer को मास्क करता है, लेकिन B, A के Layer को मास्क नहीं करता। A पर move_and_slide() B से टकराएगा, लेकिन B पर move_and_slide() A से होकर गुज़र जाएगा। दो CharacterBody नोड्स को एक-दूसरे को रोकने के लिए, दोनों को अपने Mask में दूसरे का Layer रखना होगा।
Godot MCP Pro के साथ Physics सेटअप को स्वचालित करें
layer चेकबॉक्स को मैन्युअल रूप से टॉगल करना बंद करें। AI को अपना पूरा collision सेटअप सेकंडों में कॉन्फ़िगर करने दें — layers के नामकरण, masks के असाइनमेंट और raycasts जोड़ने सहित।
Godot MCP Pro प्राप्त करें — $15setup_collision
set_physics_layers
get_physics_layers
get_collision_info
add_raycast