1. परिचय
Godot 4 ने कैरेक्टर मूवमेंट में बड़े बदलाव पेश किए। पुराने KinematicBody2D और KinematicBody3D नोड्स का नाम बदलकर CharacterBody2D और CharacterBody3D कर दिया गया, और move_and_slide() API को पूरी तरह से नया रूप दिया गया। चाहे आप Godot 3 से माइग्रेट कर रहे हों या बिल्कुल नए सिरे से शुरू कर रहे हों — यह गाइड वह सब कुछ कवर करती है जो आपको जानना ज़रूरी है।
CharacterBody2D और CharacterBody3D ऐसे फ़िज़िक्स बॉडी हैं जो कोड द्वारा नियंत्रित कैरेक्टर्स के लिए बनाए गए हैं। RigidBody के विपरीत, ये बलों पर अपने आप प्रतिक्रिया नहीं करते — आप इनकी गति को पूरी तरह स्क्रिप्ट के ज़रिए नियंत्रित करते हैं। इसीलिए ये प्लेयर कैरेक्टर्स, NPCs और हर उस चीज़ के लिए आदर्श हैं जिसे सटीक, नियतात्मक (deterministic) गति की ज़रूरत हो।
2. Godot 3 की तुलना में क्या बदला
Godot 3 और Godot 4 के बीच कैरेक्टर मूवमेंट के सबसे महत्वपूर्ण बदलाव यहाँ दिए गए हैं:
-
अब
KinematicBody2Dकी जगहCharacterBody2Dआ गया है -
अब
KinematicBody3Dकी जगहCharacterBody3Dआ गया है -
velocityअब एक बिल्ट-इन प्रॉपर्टी है — अब आप इसेmove_and_slide()को पास नहीं करते -
move_and_slide()अब कोई आर्गुमेंट नहीं लेता — यह सीधेvelocityप्रॉपर्टी से पढ़ता है -
move_and_slide_with_snap()हटा दिया गया — इसके बजायfloor_snap_lengthप्रॉपर्टी का उपयोग करें -
is_on_floor(),is_on_wall(),is_on_ceiling()पहले की तरह ही काम करते हैं -
प्रोजेक्ट के डिफ़ॉल्ट ग्रैविटी को Vector के रूप में पढ़ने के लिए
get_gravity()को Godot 4.4 में जोड़ा गया — बहुत सुविधाजनक
Godot 3 में move_and_slide() परिणामी वेलोसिटी लौटाता था। Godot 4 में यह एक bool लौटाता है (कि टक्कर हुई या नहीं), और वेलोसिटी सीधे velocity प्रॉपर्टी में अपडेट हो जाती है।
3. बुनियादी 2D प्लेटफ़ॉर्मर कंट्रोलर
यह मानक साइड-स्क्रोलिंग प्लेटफ़ॉर्मर कंट्रोलर है। कैरेक्टर बाएँ/दाएँ चल सकता है और ज़मीन पर होने पर कूद सकता है। यह वही टेम्पलेट है जो Godot नया CharacterBody2D स्क्रिप्ट बनाते समय जनरेट करता है।
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
func _physics_process(delta: float) -> void:
# Apply gravity when not on floor
if not is_on_floor():
velocity += get_gravity() * delta
# Jump when on floor and jump pressed
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Horizontal movement
var direction := Input.get_axis("ui_left", "ui_right")
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
पंक्ति-दर-पंक्ति व्याख्या
-
extends CharacterBody2D— स्क्रिप्ट CharacterBody2D से इनहेरिट करती है, जिससे हमेंvelocity,move_and_slide(),is_on_floor()आदि तक पहुँच मिलती है। -
SPEED = 300.0— क्षैतिज (horizontal) गति, पिक्सेल प्रति सेकंड में। -
JUMP_VELOCITY = -400.0— ऋणात्मक, क्योंकि 2D में Y-अक्ष नीचे की ओर इंगित करती है। ऋणात्मक मान कैरेक्टर को ऊपर की ओर ले जाता है। -
get_gravity() * delta— हर फ़्रेम में प्रोजेक्ट ग्रैविटी लागू करता है।get_gravity()नीचे की ओर इंगित करने वालाVector2लौटाता है (जैसेVector2(0, 980))।deltaसे गुणा करने पर यह फ़्रेम-रेट से स्वतंत्र हो जाता है। -
Input.get_axis("ui_left", "ui_right")— कौन-सी दिशा कुंजी दबाई गई है, उसके अनुसार -1.0 से 1.0 तक का float लौटाता है। एनालॉग इनपुट को सपोर्ट करता है। -
move_toward(velocity.x, 0, SPEED)— जब कोई इनपुट न हो तो सहजता से शून्य तक धीमा कर देता है। तीसरा आर्गुमेंट प्रति कॉल अधिकतम परिवर्तन है। -
move_and_slide()— बॉडी को वर्तमानvelocityके अनुसार चलाता है, टक्करों को संभालता है, सतहों के साथ फिसलता है, औरvelocityको अपने आप अपडेट कर देता है।
आपके CharacterBody2D को कम से कम एक CollisionShape2D चाइल्ड नोड चाहिए जिस पर कोई शेप असाइन हो (जैसे RectangleShape2D या CapsuleShape2D)। इसके बिना move_and_slide() किसी भी टक्कर का पता नहीं लगाएगा।
4. बुनियादी 2D टॉप-डाउन कंट्रोलर
टॉप-डाउन गेम्स (RPGs, ट्विन-स्टिक शूटर आदि) के लिए आप बिना ग्रैविटी के चारों दिशाओं में चलते हैं। कोड प्लेटफ़ॉर्मर की तुलना में सरल है।
extends CharacterBody2D
const SPEED = 200.0
func _physics_process(delta: float) -> void:
var input_direction := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
velocity = input_direction * SPEED
move_and_slide()
यह कैसे काम करता है
-
Input.get_vector()चार इनपुट एक्शन्स से एक सामान्यीकृत (normalized)Vector2लौटाता है। इससे तिरछी (diagonal) गति सही ढंग से संभली जाती है — वेक्टर की लंबाई हमेशा 1.0 या 0.0 होती है, इसलिए तिरछी गति अक्षों के साथ की गति से तेज़ नहीं होती। -
कोई ग्रैविटी लागू नहीं होती, क्योंकि यह टॉप-डाउन व्यू है। जब कोई इनपुट न हो तो कैरेक्टर तुरंत रुक जाता है, क्योंकि हम
velocityको सीधे सेट करते हैं (कोई जड़त्व/inertia नहीं)।
त्वरण और घर्षण जोड़ना
त्वरण और मंदन के साथ अधिक सहज अनुभव के लिए:
extends CharacterBody2D
const SPEED = 200.0
const ACCELERATION = 1200.0
const FRICTION = 1000.0
func _physics_process(delta: float) -> void:
var input_direction := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
if input_direction != Vector2.ZERO:
velocity = velocity.move_toward(input_direction * SPEED, ACCELERATION * delta)
else:
velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)
move_and_slide()
5. 3D थर्ड-पर्सन कंट्रोलर
3D संस्करण उसी पैटर्न का पालन करता है। मुख्य अंतर यह है कि यहाँ Vector3 के साथ काम किया जाता है और 2D इनपुट को 3D वर्ल्ड-स्पेस मूवमेंट में बदलने के लिए transform.basis का उपयोग किया जाता है।
extends CharacterBody3D
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
func _physics_process(delta: float) -> void:
# Apply gravity
if not is_on_floor():
velocity += get_gravity() * delta
# Jump
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get input and convert to 3D direction
var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
2D से मुख्य अंतर
-
इकाइयाँ: 3D में 1 इकाई = 1 मीटर (परंपरा)। इसलिए
SPEED = 5.0का अर्थ है 5 मीटर प्रति सेकंड — 2D पिक्सेल मानों की तुलना में बहुत छोटी संख्याएँ। -
जंप वेलोसिटी धनात्मक है: 3D में Y-अक्ष ऊपर की ओर इंगित करती है (2D के विपरीत), इसलिए
JUMP_VELOCITY = 4.5धनात्मक है। -
दिशा रूपांतरण:
transform.basis * Vector3(input_dir.x, 0, input_dir.y)2D इनपुट को कैरेक्टर की दिशा के सापेक्ष 3D दिशा में बदलता है। इनपुट का Y, Z-अक्ष (3D में आगे/पीछे) पर मैप होता है। -
केवल X और Z नियंत्रित होते हैं: हम
velocity.xऔरvelocity.zको अलग-अलग सेट करते हैं, औरvelocity.yको ग्रैविटी और कूदने के लिए छोड़ देते हैं।
get_gravity() मेथड Godot 4.4 में जोड़ा गया था। पुराने संस्करणों के लिए, 2D हेतु Vector2(0, ProjectSettings.get_setting("physics/2d/default_gravity")) या 3D हेतु Vector3(0, -ProjectSettings.get_setting("physics/3d/default_gravity"), 0) का उपयोग करें।
6. मुख्य प्रॉपर्टीज़ का संदर्भ
CharacterBody2D और CharacterBody3D दोनों इन महत्वपूर्ण प्रॉपर्टीज़ को साझा करते हैं। इन्हें इंस्पेक्टर में या कोड के ज़रिए समायोजित करें।
| प्रॉपर्टी | टाइप | डिफ़ॉल्ट | विवरण |
|---|---|---|---|
velocity |
Vector2 / Vector3 | Vector2.ZERO |
कैरेक्टर की वेलोसिटी। move_and_slide() कॉल करने से पहले इसे सेट करें। कॉल के बाद यह परिणामी वेलोसिटी के साथ अपडेट हो जाती है।
|
floor_snap_length |
float | 1.0 |
move_and_slide_with_snap() का स्थान लेता है। वह दूरी जिससे कैरेक्टर को फ़्लोर से स्नैप किया जाता है। इसे निष्क्रिय करने के लिए 0 पर सेट करें। ढलानों और सीढ़ियों के लिए उपयोगी।
|
up_direction |
Vector2 / Vector3 | Vector2.UP |
यह तय करता है कि कौन-सी दिशा "ऊपर" है। इससे यह निर्धारित होता है कि क्या फ़्लोर, दीवार या छत के रूप में गिना जाए। डिफ़ॉल्ट 2D में (0, -1) और 3D में (0, 1, 0) है।
|
floor_stop_on_slope |
bool | true |
true होने पर, स्थिर खड़े रहते समय कैरेक्टर ढलानों से नीचे नहीं फिसलता। प्लेटफ़ॉर्मर के लिए अनिवार्य। |
floor_max_angle |
float | 0.785 (45°) |
रेडियन में अधिकतम चलने योग्य ढलान कोण। इससे अधिक तीव्र सतहों को दीवारों की तरह माना जाता है। 60 डिग्री सेट करने के लिए deg_to_rad(60) का उपयोग करें।
|
max_slides |
int | 6 |
प्रति move_and_slide() कॉल टक्कर पुनरावृत्तियों (iterations) की अधिकतम संख्या। अधिक मान अधिक सटीक होते हैं, पर धीमे होते हैं।
|
wall_min_slide_angle |
float | 0.262 (15°) |
दीवार पर फिसलने के लिए न्यूनतम कोण। कैरेक्टर को लगभग समानांतर दीवारों पर अटकने से रोकता है। |
platform_on_leave |
PlatformOnLeave | ADD_VELOCITY |
चलती-फिरती प्लेटफ़ॉर्म को छोड़ते समय का व्यवहार। ADD_VELOCITY संवेग (momentum) को बनाए रखता है, ADD_UPWARD_VELOCITY केवल ऊपर की ओर वाला घटक जोड़ता है, DO_NOTHING प्लेटफ़ॉर्म की वेलोसिटी को अनदेखा करता है।
|
slide_on_ceiling |
bool | true |
true होने पर, छत पर फिसलने की अनुमति देता है। false होने पर, छत से टकराने पर क्षैतिज वेलोसिटी रुक जाती है। |
7. move_and_slide() के बाद टक्कर का पता लगाना
move_and_slide() कॉल करने के बाद, आप हुई टक्करों का निरीक्षण कर सकते हैं। यह विशिष्ट कोलाइडर प्रकारों पर प्रतिक्रिया देने, उतरते समय साउंड इफ़ेक्ट चलाने, या वॉल-जंप मैकेनिक्स लागू करने के लिए उपयोगी है।
func _physics_process(delta: float) -> void:
# ... set velocity here ...
move_and_slide()
# Check all collisions from this frame
for i in get_slide_collision_count():
var collision := get_slide_collision(i)
var collider := collision.get_collider()
print("Collided with: ", collider.name)
print("Normal: ", collision.get_normal())
print("Position: ", collision.get_position())
# Practical example: bounce off enemies
for i in get_slide_collision_count():
var collision := get_slide_collision(i)
if collision.get_collider().is_in_group("enemies"):
velocity = collision.get_normal() * 300
break
उपयोगी KinematicCollision मेथड्स
get_collider()— वह ऑब्जेक्ट जिससे टक्कर हुई।get_normal()— टक्कर की सतह का normal। सतह से दूर की ओर इंगित करता है।get_position()— वर्ल्ड स्पेस में वह बिंदु जहाँ टक्कर हुई।get_travel()— टक्कर से पहले बॉडी कितनी दूर तक चली।get_remainder()— बची हुई गति जो लागू नहीं की गई।get_collider_velocity()— कोलाइडर की वेलोसिटी (चलती-फिरती प्लेटफ़ॉर्म के लिए उपयोगी)।
8. माइग्रेशन चीट शीट
Godot 3 कोड को Godot 4 में फिर से लिखने के लिए त्वरित संदर्भ:
| Godot 3 | Godot 4 |
|---|---|
KinematicBody2D |
CharacterBody2D |
KinematicBody3D |
CharacterBody3D |
velocity = move_and_slide(velocity, Vector2.UP) |
velocity = ... |
move_and_slide_with_snap(vel, snap, up) |
floor_snap_length = 4.0 |
var vel = move_and_slide(...)velocity लौटाता है |
move_and_slide()velocity प्रॉपर्टी सीधे अपडेट होती है |
var gravity = ProjectSettings.get("physics/2d/default_gravity") |
get_gravity() (4.4+) |
move_and_slide(..., up_direction, ...) |
up_direction = Vector2.UP (प्रॉपर्टी के रूप में सेट) |
move_and_slide(..., stop_on_slope, ...) |
floor_stop_on_slope = true (प्रॉपर्टी के रूप में सेट) |
जब आप कोई Godot 3 प्रोजेक्ट Godot 4 में खोलते हैं, तो इंजन आपके प्रोजेक्ट को कन्वर्ट करने का प्रस्ताव देता है। यह नोड्स का नाम बदल देता है और स्क्रिप्ट्स को अपडेट करने की कोशिश करता है, लेकिन move_and_slide() कॉल्स को हमेशा सही ढंग से नहीं संभाल पाता। संभवतः आपको अपने मूवमेंट कोड को मैन्युअल रूप से ठीक करना पड़ेगा।
9. आम गलतियाँ
गलती 1: move_and_slide() को आर्गुमेंट पास करना
# ERROR: move_and_slide() takes no arguments in Godot 4
velocity = move_and_slide(velocity, Vector2.UP)
# Set velocity, then call move_and_slide() with no arguments
velocity.x = direction * SPEED
move_and_slide()
गलती 2: move_and_slide() से पहले velocity सेट करना भूल जाना
func _physics_process(delta: float) -> void:
move_and_slide() # velocity is Vector2.ZERO — nothing happens
गलती 3: _physics_process() के बजाय _process() का उपयोग करना
move_and_slide() को _physics_process() में कॉल किया जाना चाहिए, जो एक निश्चित दर पर चलता है (डिफ़ॉल्ट रूप से 60 Hz)। _process() का उपयोग फ़िज़िक्स को रेंडर फ़्रेम-रेट से जोड़ देता है और असंगत व्यवहार की ओर ले जाता है।
गलती 4: CollisionShape सेट अप न करना
बिना CollisionShape चाइल्ड वाला CharacterBody2D/CharacterBody3D हर चीज़ के आर-पार निकल जाता है। कोलिज़न शेप न होने पर Godot एडिटर में एक चेतावनी चिह्न दिखाता है।
गलती 5: हर फ़्रेम में velocity.y को ग्रैविटी से अधिलेखित (overwrite) करना
# This overwrites any jump velocity!
velocity.y = gravity * delta # should be +=, not =
# Gravity accumulates over time
velocity += get_gravity() * delta
गलती 6: ज़मीन पर होते हुए ग्रैविटी लागू करना
ग्रैविटी को हमेशा if not is_on_floor() के भीतर लपेटें। इस जाँच के बिना, ज़मीन पर होते हुए भी ग्रैविटी संचित होती रहती है। जब कैरेक्टर किसी किनारे से चलता है, तो वह स्वाभाविक रूप से गिरने के बजाय अत्यधिक गति से नीचे गिर जाता है।