AnimationTree Durum Makineleri
Godot 4'te
Durum makineleri, geçişler, blend tree'ler, OneShot, travel() ve koşullara dair eksiksiz rehber — gerçek GDScript kod örnekleriyle.
İçindekiler
1. Giriş
AnimationTree, Godot 4'ün karmaşık animasyon blend'i ve durum geçişleri için sunduğu sistemdir. Kodunuzun her yerine dağılmış AnimationPlayer.play() çağrılarıyla birden fazla animasyonu yönetmeye çalıştıysanız, bunun ne kadar çabuk kontrolden çıktığını bilirsiniz. AnimationTree, bunu görsel bir durum ve geçiş grafiğiyle çözer.
Son derece güçlü olmasına rağmen AnimationTree'nin resmi dokümantasyonu yetersizdir ve geliştiricileri sıklıkla tahmin yürütmek zorunda bırakır. Bu rehber, temel kurulumdan ileri düzey blend tree'lere kadar her şeyi, projenize doğrudan kopyalayabileceğiniz gerçek GDScript koduyla adım adım anlatır.
Durum makineleri, geçişler, blend space'ler (1D & 2D), saldırılar için OneShot, travel() ve koşullar ve eksiksiz bir karakter kontrolcüsü deseni.
2. Ön Koşullar
AnimationTree'nizi kurmadan önce şunlara ihtiyacınız var:
- En azından Idle, Walk, Run ve Jump animasyonları önceden oluşturulmuş bir
AnimationPlayernode'u - AnimationPlayer, AnimationTree'yi eklediğiniz node'un kardeşi veya alt öğesi olmalıdır (genellikle her ikisi de karakter kök node'unuzun alt öğeleridir)
- Godot 4.x (bu rehber Godot 4 API'sini kullanır — AnimationTree API'si Godot 3'e kıyasla önemli ölçüde değişti)
Godot 4'te AnimationTree.animation_player yerini AnimationTree.anim_player'a bıraktı. Oynatma için parametre yolu da değişti. Godot 3'ten geçiş yapıyorsanız resmi geçiş rehberine göz atın.
3. Temel Kurulum
Bir AnimationTree'nin kurulumu dört adımda gerçekleşir:
-
Bir AnimationTree node'u ekleyin
— Onu, AnimationPlayer'ınızın yanında karakterinizin (ör.
CharacterBody2DveyaCharacterBody3D) alt öğesi olarak ekleyin. -
anim_playerayarlayın — Inspector'da "Anim Player" özelliğini AnimationPlayer node'unuza yönlendirin. -
tree_rootayarlayın — Inspector'da "Tree Root" özelliğine tıklayın ve yeni birAnimationNodeStateMachineoluşturun. -
active = trueyapın — Inspector'da "Active" onay kutusunu işaretleyin veya koddan ayarlayın.
Sahne ağacınız şöyle görünmelidir:
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
Pratikte AnimationTree'yi neredeyse her zaman editörde yapılandırırsınız. Yukarıdaki kod bütünlük için verilmiştir, ancak genellikle betiğinizde yalnızca anim_tree.active = true'ya ihtiyacınız olur (ve bunu bile editörde ayarlayabilirsiniz).
4. Durum Makinesi Temelleri
AnimationTree'deki bir durum makinesi basit bir kavrama dayanır: durumlar animasyonları temsil eder ve geçişler bunlar arasında geçiş yapma koşullarını tanımlar.
Durum Ekleme
AnimationTree'nizin tree_root'u bir AnimationNodeStateMachine olduğunda, durum makinesi editörünü açmak için Inspector'da üzerine çift tıklayın:
- Grafik alanına sağ tıklayın ve Add Animation seçeneğini seçin
- AnimationPlayer'ınızdan bir animasyon seçin (Idle, Walk, Run, Jump vb.)
- İhtiyacınız olan her animasyon durumu için tekrarlayın
Start giriş noktasıdır — ilk geçiş her zaman burada başlar. End isteğe bağlıdır ve durum makinesinin tamamlandığını belirtir (iç içe durum makineleri için kullanışlıdır).
Geçiş Ekleme
İki durum arasında bir geçiş oluşturmak için:
- Kaynak durum node'una tıklayın
- Bir geçiş oku oluşturmak için hedef duruma sürükleyin
- Inspector'da yapılandırmak için geçiş okuna tıklayın
Geçiş Özellikleri
| Özellik | Açıklama |
|---|---|
advance_mode |
Auto — koşulu doğru olduğunda tetiklenir. Enabled — travel() için her zaman kullanılabilir. Disabled — engellenir. |
advance_condition |
Bir boolean parametresinin adı (ör. is_moving). Doğru olduğunda geçiş otomatik tetiklenir. |
xfade_time |
Saniye cinsinden crossfade süresi. Animasyonlar arasında yumuşak blend. Tipik: 0,1 – 0,3 sn. |
switch_mode |
Immediate — hemen geç. Sync — oynatma konumunu eşle. AtEnd — mevcut animasyonun bitmesini bekle. |
Bir platform oyunu karakteri için tipik bir kurulum:
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. Durum Makinesini Koddan Kontrol Etme
Durum makinesini yönlendirmenin iki temel yolu vardır: koşul parametreleri ayarlamak (otomatik geçişler) ve travel() çağırmak (manuel geçişler). Her iki yaklaşımı birleştirebilirsiniz.
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")
Parametreler, geçişlerde ayarlanan koşullar için parameters/conditions/<condition_name> desenini izler. Koşul adı, editörde geçişte ayarladığınız advance_condition ile eşleşmelidir.
6. travel() ve Koşullar
Koşul Tabanlı (Hareket için Önerilir)
Her karede boolean parametreleri ayarlayın ve geçişlerin otomatik tetiklenmesine izin verin. Bu daha bildirimseldir ve kodunuzu temiz tutar. Durum makinesi, geçiş mantığını, crossfade'leri ve uç durumları sizin yerinize halleder.
# 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() (Tek Seferlik Aksiyonlar için Önerilir)
travel() bir durum geçişi talep eder. Geçiş kurallarına uyar — mevcut durumdan hedefe geçerli bir yol yoksa çağrı yok sayılır. Bu, onu tekrar tekrar çağırmayı güvenli kılar. Saldırılar, emote'lar veya ara sahne animasyonları gibi tek seferlik tetikleyiciler için kullanın.
# 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)
Koşullar, sürekli durumlar (idle, walk, run, fall) için. travel(), olay tetiklemeli durumlar (saldırı, kaçınma, etkileşim) için. Birçok proje her ikisini de kullanır: hareket için koşullar, savaş aksiyonları için travel().
7. Blend Tree'ler
Blend tree'ler, ayrık durumlar arasında sert geçiş yapmak yerine sürekli bir değere göre birden fazla animasyon arasında yumuşakça enterpolasyon yapmanızı sağlar. Yürüme/koşma hızı blend'i ve yönlü hareket için mükemmeldir.
BlendSpace1D
Tek bir eksen boyunca iki veya daha fazla animasyon arasında bir 1D blend. Yaygın kullanım: hareket hızına göre Walk ile Run'ın blend'lenmesi.
Editörde, durum makinenizin içinde (veya bağımsız bir tree root olarak) bir BlendSpace1D node'u oluşturun. Animasyon noktaları ekleyin:
# 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
İki eksen kullanan bir 2D blend. 8 yönlü hareket veya karakterin herhangi bir yöne hareket edebildiği yukarıdan bakışlı oyunlar için mükemmeldir.
# 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 birden fazla blend modunu destekler: varsayılan üçgenleme çoğu durumda iyi çalışır. Enterpolasyon olmadan piksel-art tarzı animasyon isterseniz ayrık modu (en yakın noktaya sıçrar) da seçebilirsiniz.
8. Yaygın Node Tipleri
AnimationTree, karmaşık animasyon davranışları oluşturmak için birleştirilebilen çeşitli node tiplerini destekler:
| Node Tipi | Kullanım Alanı |
|---|---|
AnimationNodeStateMachine |
Geçişli durum makinesi. En yaygın kök node. Durumlar animasyonlar veya iç içe durum makineleri olabilir. |
AnimationNodeBlendSpace1D |
Tek eksen boyunca 1D blend. Yürüme/koşma hızı, nişan açısı vb. |
AnimationNodeBlendSpace2D |
İki eksen kullanan 2D blend. Yönlü hareket, yan yürüme (strafe) blend'i. |
AnimationNodeBlendTree |
Blend işlemlerinden oluşan bir grafik. Birden fazla blend node'unu özel mantıkla birleştirir. |
AnimationNodeAdd2 |
Toplamsal blend. Bir animasyonu diğerinin üzerine katmanlar (ör. yürümenin üzerine nişan ofseti). |
AnimationNodeTimeScale |
Hız kontrolü. Bir animasyonu çalışma zamanında daha hızlı veya daha yavaş oynatır. |
AnimationNodeOneShot |
Tek seferlik animasyon katmanı. Saldırılar, emote'lar, isabet tepkileri için mükemmel. |
AnimationNodeTransition |
Crossfade'lerle birden fazla giriş arasında geçiş yapar. Daha basit kurulumlar için durum makinelerine alternatif. |
9. OneShot Deseni (Saldırılar, Emote'lar)
OneShot node'u AnimationTree'deki en kullanışlı desenlerden biridir. Temel animasyonunuzun üzerinde tek seferlik bir animasyon oynatır (yürürken bir saldırı savurmasını oynatmak gibi) ve ardından otomatik olarak temel animasyona döner.
BlendTree İçinde Kurulum
OneShot kullanmak için AnimationTree kökünüzün (veya içindeki bir durumun) bir BlendTree olması gerekir:
# 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.
Koddan Tetikleme
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 İstek Sabitleri
| Sabit | Etki |
|---|---|
ONE_SHOT_REQUEST_FIRE |
OneShot animasyonunu oynatmaya başlar |
ONE_SHOT_REQUEST_ABORT |
OneShot'ı iptal eder ve hemen temele döner |
ONE_SHOT_REQUEST_FADE_OUT |
OneShot'ı kaybolarak söndürür (fadeout_time özelliğini kullanır) |
Kombo sistemleri için, ardışık olarak birden fazla OneShot node'u kullanın veya OneShot'ın "shot" girişinde Attack1 → Attack2 → Attack3 durumlarına sahip iç içe bir durum makinesi kullanın.
10. Pratik Örnek: Eksiksiz Karakter Kontrolcüsü
İşte durum makinesi hareketini bir OneShot saldırısıyla birleştiren eksiksiz bir 2D platform oyunu karakter betiği. Bu, kendi projenize uyarlayabileceğiniz üretime hazır bir desendir.
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
)
Kök = BlendTree. İçinde: bir StateMachine node'u (Idle/Walk/Run/Jump/Fall durumlarıyla) bir OneShot node'una ("AttackOneShot") bağlı, o da Output'a bağlı. Saldırı animasyonu OneShot'ın "shot" girişine bağlıdır.
11. Sorun Giderme
AnimationTree üzerinde active = true olduğunu ve anim_player özelliğinin geçerli bir AnimationPlayer'a işaret ettiğini kontrol edin. Ayrıca AnimationPlayer'ın referans verdiğiniz adlara sahip animasyonları gerçekten içerdiğini doğrulayın.
Mevcut durum ile hedef durum arasında geçerli bir geçiş yolu bulunduğundan emin olun. travel(), bir yol yoksa sessizce başarısız olur. Aslında hangi durumda olduğunuzu hata ayıklamak için state_machine.get_current_node() kullanın.
blend_position değerinizin blend space noktalarınızın aralığına düştüğünü kontrol edin. Noktalarınız 0.0 ve 1.0'daysa, 5.0 değeri beklendiği gibi çalışmaz. clamp() kullanın.
active = true'yu editörde (Inspector onay kutusu) veya _ready() fonksiyonunuzda ayarlayın. AnimationTree etkinleştirilene kadar hiçbir şey yapmaz.
Şunları dikkatlice kontrol edin: (1) geçişin advance_mode değerinin Auto olarak ayarlandığını, (2) advance_condition adının kodda ayarladığınızla tam olarak eşleştiğini (büyük/küçük harfe duyarlı), ve (3) parametreyi _physics_process() içinde her karede ayarladığınızı.
AnimationTree yalnızca animasyon oynatmayı yönetir. Hareket mantığı (velocity, move_and_slide()) bundan ayrıdır ve betiğinizin _physics_process() fonksiyonunda uygulanmalıdır.
AnimationTree'nizi Yapay Zekânın Kurmasını İster misiniz?
Godot MCP Pro durum makineleri oluşturabilir, durumlar ve geçişler ekleyebilir, blend tree'leri yapılandırabilir ve parametreler ayarlayabilir — hepsi tek bir prompt'tan. Yapay zeka asistanınıza istediğiniz animasyon davranışını söyleyin, o da tüm AnimationTree'yi sizin için kursun.
- create_animation_tree
- add_state_machine_state
- add_state_machine_transition
- set_blend_tree_node
- set_tree_parameter
- get_animation_tree_structure