godot-animation-tree-mastery

安装量: 62
排名: #12125

安装

npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-animation-tree-mastery
AnimationTree Mastery
Expert guidance for Godot's advanced animation blending and state machines.
NEVER Do
NEVER call
play()
on AnimationPlayer when using AnimationTree
— AnimationTree controls the player. Directly calling
play()
causes conflicts. Use
set("parameters/transition_request")
instead.
NEVER forget to set
active = true
— AnimationTree is inactive by default. Animations won't play until
$AnimationTree.active = true
.
NEVER use absolute paths for transition_request
— Use relative paths. "parameters/StateMachine/transition_request", not "/root/.../transition_request".
NEVER leave auto_advance enabled unintentionally
— Auto-advance transitions fire immediately without conditions. Useful for combo chains, but deadly for idle→walk.
NEVER use BlendSpace2D for non-directional blending
— Use BlendSpace1D for speed (walk→run) or Blend2 for simple tweens. BlendSpace2D is for X+Y axes (strafe animations).
Available Scripts
MANDATORY
Read the appropriate script before implementing the corresponding pattern. nested_state_machine.gd Hierarchical state machine pattern. Shows travel() between sub-states and deep parameter paths (StateMachine/BlendSpace2D/blend_position). skeleton_ik_lookat.gd Procedural IK for head-tracking. Drives SkeletonModifier3D look-at parameters from AnimationTree with smooth weight blending. Core Concepts AnimationTree Structure AnimationTree (node) ├─ Root (assigned in editor) │ ├─ StateMachine (common) │ ├─ BlendTree (layering) │ └─ BlendSpace (directional) └─ anim_player: NodePath → points to AnimationPlayer Parameter Access

Set parameters using string paths

$AnimationTree . set ( "parameters/StateMachine/transition_request" , "run" ) $AnimationTree . set ( "parameters/Movement/blend_position" , Vector2 ( 1 , 0 ) )

Get current state

var current_state = $AnimationTree . get ( "parameters/StateMachine/current_state" ) StateMachine Pattern Basic Setup

Scene structure:

CharacterBody2D

├─ AnimationPlayer (has: idle, walk, run, jump, land)

└─ AnimationTree

└─ Root: AnimationNodeStateMachine

StateMachine nodes (created in AnimationTree editor):

- Idle (AnimationNode referencing "idle")

- Walk (AnimationNode referencing "walk")

- Run (AnimationNode referencing "run")

- Jump (AnimationNode referencing "jump")

- Land (AnimationNode referencing "land")

@ onready var anim_tree : AnimationTree = $AnimationTree @ onready var state_machine : AnimationNodeStateMachinePlayback = anim_tree . get ( "parameters/StateMachine/playback" ) func _ready ( ) -> void : anim_tree . active = true func _physics_process ( delta : float ) -> void : var velocity := get_velocity ( )

State transitions based on gameplay

if is_on_floor ( ) : if velocity . length ( ) < 10 : state_machine . travel ( "Idle" ) elif velocity . length ( ) < 200 : state_machine . travel ( "Walk" ) else : state_machine . travel ( "Run" ) else : if velocity . y < 0 :

Rising

state_machine . travel ( "Jump" ) else :

Falling

state_machine . travel ( "Land" ) Transition Conditions (Advance Expressions)

In AnimationTree editor:

Add transition from Idle → Walk

Set "Advance Condition" to "is_walking"

In code:

anim_tree . set ( "parameters/conditions/is_walking" , true )

Transition fires automatically when condition becomes true

Useful for event-driven transitions (hurt, dead, etc.)

Example: Damage transition

anim_tree . set ( "parameters/conditions/is_damaged" , false )

Reset each frame

func take_damage ( ) -> void : anim_tree . set ( "parameters/conditions/is_damaged" , true )

Transition to "Hurt" state fires immediately

Auto-Advance (Combo Chains)

In AnimationTree editor:

Transition from Attack1 → Attack2

Enable "Auto Advance" (no condition needed)

Code:

state_machine . travel ( "Attack1" )

Attack1 animation plays

When Attack1 finishes, automatically transitions to Attack2

When Attack2 finishes, transitions to Idle (next auto-advance)

Useful for:

- Attack combos

- Death → Respawn

- Cutscene sequences

BlendSpace2D (Directional Movement) 8-Way Movement

Create BlendSpace2D in AnimationTree editor:

- Add animations at positions:

- (0, -1): walk_up

- (0, 1): walk_down

- (-1, 0): walk_left

- (1, 0): walk_right

- (-1, -1): walk_up_left

- (1, -1): walk_up_right

- (-1, 1): walk_down_left

- (1, 1): walk_down_right

- (0, 0): idle (center)

In code:

func _physics_process ( delta : float ) -> void : var input := Input . get_vector ( "left" , "right" , "up" , "down" )

Set blend position (AnimationTree interpolates between animations)

anim_tree . set ( "parameters/Movement/blend_position" , input )

BlendSpace2D automatically blends animations based on input

input = (0.5, -0.5) → blends walk_right and walk_up

BlendSpace1D (Speed Blending)

For walk → run transitions

Create BlendSpace1D:

- Position 0.0: walk

- Position 1.0: run

func _physics_process ( delta : float ) -> void : var speed := velocity . length ( ) var max_speed := 400.0 var blend_value := clamp ( speed / max_speed , 0.0 , 1.0 ) anim_tree . set ( "parameters/SpeedBlend/blend_position" , blend_value )

Smoothly blends from walk → run as speed increases

BlendTree (Layered Animations) Add Upper Body Animation

Problem: Want to aim gun while walking

Solution: Blend upper body (aim) with lower body (walk)

In AnimationTree editor:

Root → BlendTree

├─ Walk (lower body animation)

├─ Aim (upper body animation)

└─ Add2 node (combines them)

- Inputs: Walk, Aim

- filter_enabled: true

- Filters: Only enable upper body bones for Aim

Code:

No code needed! BlendTree auto-combines

Just ensure animations are assigned

Blend2 (Crossfade)

Blend between two animations dynamically

Root → BlendTree

└─ Blend2

├─ Input A: idle

└─ Input B: attack

Code:

var blend_amount := 0.0 func _process ( delta : float ) -> void :

Gradually blend from idle → attack

blend_amount += delta blend_amount = clamp ( blend_amount , 0.0 , 1.0 ) anim_tree . set ( "parameters/IdleAttackBlend/blend_amount" , blend_amount )

0.0 = 100% idle

0.5 = 50% idle, 50% attack

1.0 = 100% attack

Root Motion with AnimationTree

Enable in AnimationTree

anim_tree . root_motion_track = NodePath ( "CharacterBody3D/Skeleton3D:Root" ) func _physics_process ( delta : float ) -> void :

Get root motion

var root_motion := anim_tree . get_root_motion_position ( )

Apply to character (not velocity!)

global_position += root_motion . rotated ( rotation . y )

For CharacterBody3D with move_and_slide:

velocity

root_motion / delta move_and_slide ( ) Advanced Patterns Sub-StateMachines

Nested state machines for complex behavior

Root → StateMachine

├─ Grounded (Sub-StateMachine)

│ ├─ Idle

│ ├─ Walk

│ └─ Run

└─ Airborne (Sub-StateMachine)

├─ Jump

├─ Fall

└─ Glide

Access nested states:

var sub_state = anim_tree . get ( "parameters/Grounded/playback" ) sub_state . travel ( "Run" ) Time Scale (Slow Motion)

Slow down specific animation without affecting others

anim_tree . set ( "parameters/TimeScale/scale" , 0.5 )

50% speed

Useful for:

- Bullet time

- Hurt/stun effects

- Charge-up animations

Sync Between Animations

Problem: Switching from walk → run causes foot slide

Solution: Use "Sync" on transition

In AnimationTree editor:

Transition: Walk → Run

Enable "Sync" checkbox

Godot automatically syncs animation playback positions

Feet stay grounded during transition

Debugging AnimationTree Print Current State func _process ( delta : float ) -> void : var current_state = anim_tree . get ( "parameters/StateMachine/current_state" ) print ( "Current state: " , current_state )

Print blend position

var blend_pos = anim_tree . get ( "parameters/Movement/blend_position" ) print ( "Blend position: " , blend_pos ) Common Issues

Issue: Animation not playing

Solution:

if not anim_tree . active : anim_tree . active = true

Issue: Transition not working

Check:

1. Is advance_condition set?

2. Is transition priority correct?

3. Is auto_advance enabled unintentionally?

Issue: Blend not smooth

Solution: Increase transition xfade_time (0.1 - 0.3s)

Performance Optimization Disable When Not Needed

AnimationTree is expensive

Disable for off-screen entities

extends
VisibleOnScreenNotifier3D
func
_ready
(
)
->
void
:
screen_exited
.
connect
(
_on_screen_exited
)
screen_entered
.
connect
(
_on_screen_entered
)
func
_on_screen_exited
(
)
->
void
:
$AnimationTree
.
active
=
false
func
_on_screen_entered
(
)
->
void
:
$AnimationTree
.
active
=
true
Decision Tree: When to Use AnimationTree
Feature
AnimationPlayer Only
AnimationTree
Simple state swap
✅ play("idle")
❌ Overkill
Directional movement
❌ Complex
✅ BlendSpace2D
State machine (5+ states)
❌ Messy code
✅ StateMachine
Layered animations
❌ Manual blending
✅ BlendTree
Root motion
✅ Possible
✅ Built-in
Transition blending
❌ Manual
✅ Auto
Use AnimationTree for
Complex characters with 5+ states, directional movement, layered animations
Use AnimationPlayer for
Simple animations, UI, cutscenes, props Reference Master Skill: godot-master
返回排行榜