AnimationTree स्टेट मशीन
Godot 4 में
स्टेट मशीन, ट्रांज़िशन, ब्लेंड ट्री, OneShot, travel() बनाम शर्तों की संपूर्ण गाइड — वास्तविक GDScript कोड उदाहरणों के साथ।
विषय-सूची
1. परिचय
AnimationTree, Godot 4 का जटिल एनिमेशन ब्लेंडिंग और स्टेट ट्रांज़िशन के लिए सिस्टम है। यदि आपने कभी अपने कोड में जगह-जगह बिखरे AnimationPlayer.play() कॉल्स के साथ कई एनिमेशन प्रबंधित करने की कोशिश की है, तो आप जानते हैं कि यह कितनी जल्दी बेकाबू हो जाता है। AnimationTree इसे स्टेट्स और ट्रांज़िशन के एक विज़ुअल ग्राफ़ के साथ हल करता है।
अत्यंत शक्तिशाली होने के बावजूद, AnimationTree का आधिकारिक डॉक्युमेंटेशन कम है और अक्सर डेवलपर्स को अनुमान लगाने पर छोड़ देता है। यह गाइड बुनियादी सेटअप से लेकर उन्नत ब्लेंड ट्री तक सब कुछ समझाती है – वास्तविक GDScript कोड के साथ जिसे आप सीधे अपने प्रोजेक्ट में कॉपी कर सकते हैं।
स्टेट मशीन, ट्रांज़िशन, ब्लेंड स्पेस (1D और 2D), हमलों के लिए OneShot, travel() बनाम शर्तें, और एक संपूर्ण कैरेक्टर कंट्रोलर पैटर्न।
2. पूर्वापेक्षाएं
अपना AnimationTree सेट करने से पहले, आपको चाहिए:
- एक
AnimationPlayerनोड जिसमें कम से कम Idle, Walk, Run और Jump एनिमेशन पहले से बने हों - AnimationPlayer उस नोड का सिबलिंग या चाइल्ड होना चाहिए जहां आप AnimationTree जोड़ते हैं (आमतौर पर दोनों आपके कैरेक्टर रूट नोड के चाइल्ड होते हैं)
- Godot 4.x (यह गाइड Godot 4 API का उपयोग करती है — AnimationTree API Godot 3 की तुलना में काफी बदल गया है)
Godot 4 में AnimationTree.animation_player को AnimationTree.anim_player से बदल दिया गया। प्लेबैक के लिए पैरामीटर पथ भी बदल गया है। यदि आप Godot 3 से माइग्रेट कर रहे हैं, तो आधिकारिक माइग्रेशन गाइड देखें।
3. बुनियादी सेटअप
AnimationTree का सेटअप चार चरणों में होता है:
-
एक AnimationTree नोड जोड़ें
— इसे अपने AnimationPlayer के साथ, अपने कैरेक्टर (जैसे
CharacterBody2DयाCharacterBody3D) के चाइल्ड के रूप में जोड़ें। -
anim_playerसेट करें — Inspector में "Anim Player" प्रॉपर्टी को अपने AnimationPlayer नोड की ओर इंगित करें। -
tree_rootसेट करें — Inspector में "Tree Root" प्रॉपर्टी पर क्लिक करें और एक नईAnimationNodeStateMachineबनाएं। -
active = trueसेट करें — Inspector में "Active" चेकबॉक्स को सक्षम करें या इसे कोड में सेट करें।
आपका सीन ट्री इस तरह दिखना चाहिए:
CharacterBody2D (or CharacterBody3D)
+-- Sprite2D (or Sprite3D)
+-- CollisionShape2D
+-- AnimationPlayer <-- has Idle, Walk, Run, Jump animations
+-- AnimationTree <-- points to AnimationPlayer above
GDScript
# Minimal code setup (usually done via the editor instead):
@onready var anim_tree: AnimationTree = $AnimationTree
func _ready() -> void:
# If you set these in the Inspector, you don't need this code
anim_tree.anim_player = ^"../AnimationPlayer"
anim_tree.tree_root = AnimationNodeStateMachine.new()
anim_tree.active = true
व्यवहार में, आप लगभग हमेशा AnimationTree को एडिटर में कॉन्फ़िगर करते हैं। ऊपर दिया गया कोड पूर्णता के लिए दिखाया गया है, लेकिन आमतौर पर आपको अपनी स्क्रिप्ट में केवल anim_tree.active = true की आवश्यकता होती है (और यह भी एडिटर में सेट किया जा सकता है)।
4. स्टेट मशीन की मूल बातें
AnimationTree में एक स्टेट मशीन एक सरल अवधारणा पर काम करती है: स्टेट्स एनिमेशन का प्रतिनिधित्व करते हैं और ट्रांज़िशन उनके बीच स्विच करने की शर्तें परिभाषित करते हैं।
स्टेट्स जोड़ना
एक बार जब आपके AnimationTree का tree_root एक AnimationNodeStateMachine हो जाए, तो स्टेट मशीन एडिटर खोलने के लिए Inspector में उस पर डबल-क्लिक करें:
- ग्राफ़ क्षेत्र में दायाँ-क्लिक करें और Add Animation चुनें
- अपने AnimationPlayer से एक एनिमेशन चुनें (Idle, Walk, Run, Jump आदि)
- आपको जितने भी एनिमेशन स्टेट चाहिए, उनके लिए इसे दोहराएं
Start प्रवेश बिंदु है — पहला ट्रांज़िशन हमेशा यहीं से शुरू होता है। End वैकल्पिक है और संकेत देता है कि स्टेट मशीन समाप्त हो गई है (नेस्टेड स्टेट मशीन के लिए उपयोगी)।
ट्रांज़िशन जोड़ना
दो स्टेट्स के बीच ट्रांज़िशन बनाने के लिए:
- स्रोत स्टेट नोड पर क्लिक करें
- ट्रांज़िशन तीर बनाने के लिए लक्ष्य स्टेट तक खींचें
- ट्रांज़िशन तीर पर क्लिक करके उसे Inspector में कॉन्फ़िगर करें
ट्रांज़िशन प्रॉपर्टीज़
| प्रॉपर्टी | विवरण |
|---|---|
advance_mode |
Auto — शर्त सही होने पर फ़ायर होता है। Enabled — travel() के लिए हमेशा उपलब्ध। Disabled — अवरुद्ध। |
advance_condition |
एक बूलियन पैरामीटर का नाम (जैसे is_moving)। सही होने पर ट्रांज़िशन स्वचालित रूप से फ़ायर होता है। |
xfade_time |
सेकंड में क्रॉसफेड अवधि। एनिमेशन के बीच सहज ब्लेंडिंग। सामान्य: 0.1 – 0.3 सेकंड। |
switch_mode |
Immediate — तुरंत स्विच करें। Sync — प्लेबैक स्थिति मिलाएं। AtEnd — वर्तमान एनिमेशन के समाप्त होने तक प्रतीक्षा करें। |
एक प्लेटफॉर्मर कैरेक्टर के लिए एक सामान्य सेटअप:
Start --> Idle
Idle --> Walk (condition: is_moving)
Walk --> Idle (condition: is_idle)
Idle --> Jump (condition: is_jumping)
Walk --> Jump (condition: is_jumping)
Jump --> Fall (condition: is_falling)
Fall --> Idle (condition: is_on_floor, switch_mode: Immediate)
5. कोड से स्टेट मशीन को नियंत्रित करना
स्टेट मशीन को चलाने के दो मुख्य तरीके हैं: कंडीशन पैरामीटर सेट करना (स्वचालित ट्रांज़िशन) और travel() को कॉल करना (मैनुअल ट्रांज़िशन)। आप दोनों दृष्टिकोणों को मिला सकते हैं।
extends CharacterBody2D
@onready var anim_tree: AnimationTree = $AnimationTree
@onready var state_machine: AnimationNodeStateMachinePlayback = anim_tree.get("parameters/playback")
func _physics_process(delta: float) -> void:
# ... movement logic here ...
move_and_slide()
_update_animation_parameters()
func _update_animation_parameters() -> void:
# Approach 1: Set condition parameters — transitions fire automatically
anim_tree.set("parameters/conditions/is_moving", velocity.length() > 10.0)
anim_tree.set("parameters/conditions/is_idle", velocity.length() <= 10.0)
anim_tree.set("parameters/conditions/is_on_floor", is_on_floor())
anim_tree.set("parameters/conditions/is_jumping", velocity.y < 0 and not is_on_floor())
anim_tree.set("parameters/conditions/is_falling", velocity.y > 0 and not is_on_floor())
# Approach 2: Use travel() for direct control
# if velocity.length() > 10.0:
# state_machine.travel("Walk")
# else:
# state_machine.travel("Idle")
ट्रांज़िशन पर सेट की गई शर्तों के लिए पैरामीटर पैटर्न parameters/conditions/<condition_name> का अनुसरण करते हैं। शर्त का नाम उस advance_condition से मेल खाना चाहिए जिसे आपने एडिटर में ट्रांज़िशन पर सेट किया था।
6. travel() बनाम शर्तें
शर्त-आधारित (चलने-फिरने के लिए अनुशंसित)
हर फ़्रेम में बूलियन पैरामीटर सेट करें और ट्रांज़िशन को स्वचालित रूप से फ़ायर होने दें। यह अधिक घोषणात्मक है और आपके कोड को साफ़ रखता है। स्टेट मशीन आपके लिए ट्रांज़िशन लॉजिक, क्रॉसफेड और एज केस को संभालती है।
# Declarative: just describe the current state of the world
anim_tree.set("parameters/conditions/is_moving", velocity.length() > 10.0)
anim_tree.set("parameters/conditions/is_on_floor", is_on_floor())
travel() (एकल-बार की क्रियाओं के लिए अनुशंसित)
travel() एक स्टेट ट्रांज़िशन का अनुरोध करता है। यह ट्रांज़िशन नियमों का सम्मान करता है — यदि वर्तमान स्टेट से लक्ष्य तक कोई मान्य पथ मौजूद नहीं है, तो कॉल को अनदेखा कर दिया जाता है। इससे इसे बार-बार कॉल करना सुरक्षित हो जाता है। इसका उपयोग हमले, इमोट्स या कटसीन एनिमेशन जैसे एकल-बार के ट्रिगर्स के लिए करें।
# travel() — requests a transition (respects transition rules)
state_machine.travel("Jump")
# Get current state name
var current: StringName = state_machine.get_current_node()
print(current) # "Idle", "Walk", etc.
# Check if travel is possible
var is_playing: bool = state_machine.is_playing()
print(is_playing)
निरंतर स्टेट्स (idle, walk, run, fall) के लिए शर्तें। इवेंट-ट्रिगर्ड स्टेट्स (attack, dodge, interact) के लिए travel()। कई प्रोजेक्ट दोनों का उपयोग करते हैं: चलने-फिरने के लिए शर्तें, युद्ध क्रियाओं के लिए travel()।
7. ब्लेंड ट्री
ब्लेंड ट्री आपको असतत स्टेट्स के बीच हार्ड-स्विचिंग के बजाय एक निरंतर मान के आधार पर कई एनिमेशन के बीच सहज रूप से इंटरपोलेट करने देते हैं। यह चलने/दौड़ने की गति की ब्लेंडिंग और दिशात्मक गति के लिए आदर्श है।
BlendSpace1D
एक ही अक्ष के साथ दो या अधिक एनिमेशन के बीच एक 1D ब्लेंड। सामान्य उपयोग: गति के आधार पर Walk और Run की ब्लेंडिंग।
एडिटर में, अपनी स्टेट मशीन के अंदर (या एक स्टैंडअलोन ट्री रूट के रूप में) एक BlendSpace1D नोड बनाएं। एनिमेशन पॉइंट जोड़ें:
# BlendSpace1D setup (in editor):
# Point 0.0 = Walk animation
# Point 1.0 = Run animation
# Control from code:
var speed_factor: float = clamp(velocity.length() / max_speed, 0.0, 1.0)
anim_tree.set("parameters/WalkRun/blend_position", speed_factor)
BlendSpace2D
दो अक्षों का उपयोग करके एक 2D ब्लेंड। 8-दिशात्मक गति या टॉप-डाउन गेम्स के लिए एकदम सही जहां कैरेक्टर किसी भी दिशा में जा सकता है।
# BlendSpace2D setup (in editor):
# Place animations at positions:
# Idle at (0, 0)
# WalkRight at (1, 0), WalkLeft at (-1, 0)
# WalkUp at (0, -1), WalkDown at (0, 1)
# Diagonals at corners
# Control from code:
var input_dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
anim_tree.set("parameters/Movement/blend_position", input_dir)
BlendSpace2D कई ब्लेंड मोड का समर्थन करता है: डिफ़ॉल्ट ट्राइएंगुलेशन अधिकांश मामलों में अच्छी तरह काम करता है। यदि आप इंटरपोलेशन के बिना पिक्सेल-आर्ट शैली का एनिमेशन चाहते हैं तो आप असतत (discrete) मोड भी चुन सकते हैं (जो निकटतम बिंदु पर स्नैप करता है)।
8. सामान्य नोड प्रकार
AnimationTree कई नोड प्रकारों का समर्थन करता है जिन्हें जटिल एनिमेशन व्यवहार बनाने के लिए संयोजित किया जा सकता है:
| नोड प्रकार | उपयोग |
|---|---|
AnimationNodeStateMachine |
ट्रांज़िशन के साथ स्टेट मशीन। सबसे आम रूट नोड। स्टेट्स एनिमेशन या नेस्टेड स्टेट मशीन हो सकते हैं। |
AnimationNodeBlendSpace1D |
एक अक्ष के साथ 1D ब्लेंड। चलने/दौड़ने की गति, लक्ष्य कोण आदि। |
AnimationNodeBlendSpace2D |
दो अक्षों का उपयोग करते हुए 2D ब्लेंड। दिशात्मक गति, स्ट्रेफ़ ब्लेंडिंग। |
AnimationNodeBlendTree |
ब्लेंड ऑपरेशनों का एक ग्राफ़। कस्टम लॉजिक के साथ कई ब्लेंड नोड्स को संयोजित करें। |
AnimationNodeAdd2 |
योगात्मक (additive) ब्लेंडिंग। एक एनिमेशन को दूसरे के ऊपर लगाएं (जैसे चलने के ऊपर एक एम ऑफ़सेट)। |
AnimationNodeTimeScale |
गति नियंत्रण। रनटाइम पर किसी एनिमेशन को तेज़ या धीमा चलाएं। |
AnimationNodeOneShot |
एकल-बार एनिमेशन ओवरले। हमले, इमोट्स, हिट रिएक्शन के लिए एकदम सही। |
AnimationNodeTransition |
क्रॉसफेड के साथ कई इनपुट के बीच स्विच करें। सरल सेटअप के लिए स्टेट मशीन का विकल्प। |
9. OneShot पैटर्न (हमले, इमोट्स)
OneShot नोड AnimationTree के सबसे उपयोगी पैटर्न में से एक है। यह आपके बेस एनिमेशन के ऊपर एक एकल-बार का एनिमेशन चलाता है (जैसे चलते समय एक अटैक स्विंग चलाना) और उसके बाद स्वचालित रूप से बेस एनिमेशन पर लौट आता है।
BlendTree में सेटअप
OneShot का उपयोग करने के लिए, आपके AnimationTree की रूट (या उसके भीतर का एक स्टेट) एक BlendTree होना चाहिए:
# BlendTree graph setup:
#
# [StateMachine] ---> [OneShot "AttackOneShot"] ---> [Output]
# (base locomotion) ^
# |
# [Animation "Attack"]
# (shot input)
#
# The StateMachine provides the base (idle/walk/run).
# The Attack animation is connected to the OneShot's "shot" input.
कोड से ट्रिगर करना
GDScriptextends CharacterBody2D
@onready var anim_tree: AnimationTree = $AnimationTree
func _input(event: InputEvent) -> void:
if event.is_action_pressed("attack"):
_play_attack()
func _play_attack() -> void:
# Fire the one-shot animation
anim_tree.set(
"parameters/AttackOneShot/request",
AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE
)
func _process(delta: float) -> void:
# Check if the one-shot is currently active
var is_attacking: bool = anim_tree.get("parameters/AttackOneShot/active")
if is_attacking:
# Optionally disable movement during attack
pass
OneShot रिक्वेस्ट कॉन्स्टेंट
| कॉन्स्टेंट | प्रभाव |
|---|---|
ONE_SHOT_REQUEST_FIRE |
OneShot एनिमेशन का प्लेबैक शुरू करता है |
ONE_SHOT_REQUEST_ABORT |
OneShot को रद्द करता है और तुरंत बेस पर लौट आता है |
ONE_SHOT_REQUEST_FADE_OUT |
OneShot को फ़ेड आउट करता है (fadeout_time प्रॉपर्टी का उपयोग करता है) |
कॉम्बो सिस्टम के लिए, क्रम में कई OneShot नोड्स का उपयोग करें या OneShot के "shot" इनपुट के भीतर Attack1 → Attack2 → Attack3 स्टेट्स वाली एक नेस्टेड स्टेट मशीन का उपयोग करें।
10. व्यावहारिक उदाहरण: संपूर्ण कैरेक्टर कंट्रोलर
यहां एक संपूर्ण 2D प्लेटफॉर्मर कैरेक्टर स्क्रिप्ट है जो स्टेट मशीन आधारित चलने-फिरने को एक OneShot हमले के साथ जोड़ती है। यह एक प्रोडक्शन-रेडी पैटर्न है जिसे आप अपने प्रोजेक्ट के अनुसार ढाल सकते हैं।
GDScript — player.gdextends CharacterBody2D
const SPEED := 200.0
const JUMP_VELOCITY := -350.0
const SPRINT_MULTIPLIER := 1.6
@onready var anim_tree: AnimationTree = $AnimationTree
@onready var playback: AnimationNodeStateMachinePlayback = anim_tree.get("parameters/playback")
@onready var sprite: Sprite2D = $Sprite2D
var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
func _ready() -> void:
anim_tree.active = true
func _physics_process(delta: float) -> void:
_apply_gravity(delta)
_handle_jump()
_handle_movement()
move_and_slide()
_update_animation()
func _apply_gravity(delta: float) -> void:
if not is_on_floor():
velocity.y += gravity * delta
func _handle_jump() -> void:
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
func _handle_movement() -> void:
var direction := Input.get_axis("move_left", "move_right")
var is_sprinting := Input.is_action_pressed("sprint")
var current_speed := SPEED * (SPRINT_MULTIPLIER if is_sprinting else 1.0)
if direction != 0.0:
velocity.x = direction * current_speed
sprite.flip_h = direction < 0.0
else:
velocity.x = move_toward(velocity.x, 0.0, SPEED)
func _update_animation() -> void:
# Skip animation updates during attack
var is_attacking: bool = anim_tree.get("parameters/AttackOneShot/active")
if is_attacking:
return
if not is_on_floor():
if velocity.y < 0:
playback.travel("Jump")
else:
playback.travel("Fall")
elif abs(velocity.x) > 10.0:
if Input.is_action_pressed("sprint"):
playback.travel("Run")
else:
playback.travel("Walk")
else:
playback.travel("Idle")
func _input(event: InputEvent) -> void:
if event.is_action_pressed("attack") and is_on_floor():
anim_tree.set(
"parameters/AttackOneShot/request",
AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE
)
Root = BlendTree. इसके अंदर: एक StateMachine नोड (Idle/Walk/Run/Jump/Fall स्टेट्स के साथ) जो एक OneShot नोड ("AttackOneShot") से जुड़ा है, जो बदले में Output से जुड़ा है। अटैक एनिमेशन OneShot के "shot" इनपुट से जुड़ा है।
11. समस्या-निवारण
जांचें कि AnimationTree पर active = true सेट है और anim_player प्रॉपर्टी एक मान्य AnimationPlayer की ओर इंगित करती है। यह भी सुनिश्चित करें कि AnimationPlayer में वास्तव में उन नामों के एनिमेशन हैं जिन्हें आप संदर्भित कर रहे हैं।
सुनिश्चित करें कि वर्तमान स्टेट और लक्ष्य स्टेट के बीच एक मान्य ट्रांज़िशन पथ मौजूद है। यदि कोई पथ मौजूद नहीं है तो travel() चुपचाप विफल हो जाता है। यह डिबग करने के लिए कि आप वास्तव में किस स्टेट में हैं, state_machine.get_current_node() का उपयोग करें।
जांचें कि आपका blend_position मान आपके ब्लेंड स्पेस पॉइंट्स की सीमा के भीतर आता है। यदि आपके पॉइंट 0.0 और 1.0 पर हैं, तो 5.0 का मान अपेक्षानुसार काम नहीं करेगा। clamp() का उपयोग करें।
एडिटर में (Inspector चेकबॉक्स) या अपने _ready() फ़ंक्शन में active = true सेट करें। जब तक इसे सक्रिय नहीं किया जाता, AnimationTree कुछ नहीं करता।
ध्यान से जांचें कि: (1) ट्रांज़िशन का advance_mode Auto पर सेट है, (2) advance_condition का नाम ठीक उसी से मेल खाता है जो आपने कोड में सेट किया है (केस-संवेदनशील), और (3) आप हर फ़्रेम में _physics_process() में पैरामीटर सेट कर रहे हैं।
AnimationTree केवल एनिमेशन प्लेबैक को संभालता है। मूवमेंट लॉजिक (velocity, move_and_slide()) इससे अलग है और इसे आपकी स्क्रिप्ट के _physics_process() में लागू किया जाना चाहिए।
चाहते हैं कि AI आपका AnimationTree बनाए?
Godot MCP Pro स्टेट मशीन बना सकता है, स्टेट्स और ट्रांज़िशन जोड़ सकता है, ब्लेंड ट्री कॉन्फ़िगर कर सकता है और पैरामीटर सेट कर सकता है — सब कुछ एक ही प्रॉम्प्ट से। अपने AI असिस्टेंट को बताएं कि आप कौन-सा एनिमेशन व्यवहार चाहते हैं, और वह आपके लिए पूरा AnimationTree बना देगा।
- create_animation_tree
- add_state_machine_state
- add_state_machine_transition
- set_blend_tree_node
- set_tree_parameter
- get_animation_tree_structure