Claude-skill-registry godot-setup-animationtree
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/godot-setup-animationtree" ~/.claude/skills/majiayu000-claude-skill-registry-godot-setup-animationtree && rm -rf "$T"
skills/data/godot-setup-animationtree/SKILL.mdSetup AnimationTree State Machine
Core Principle
Animation is state-driven, not frame-driven. Use AnimationTree to manage animation states, BlendSpaces for smooth parameter blending, and transitions for state changes. Avoid direct AnimationPlayer playback in gameplay code.
What This Skill Does
Sets up complete AnimationTree systems:
- AnimationTree Node Structure - Creates the tree node and animation player binding
- AnimationNodeStateMachine - Builds state machine graphs with entry/exit states
- BlendSpace2D/3D - Configures locomotion blending based on velocity/input
- State Transitions - Defines conditions (bool, expression, time-based) for state changes
- Blend Trees - Creates complex animation mixing with OneShot, Add2, Blend2 nodes
AnimationTree Setup
Basic AnimationTree Configuration
Before (Direct AnimationPlayer):
# player_animation.gd - Manual animation management extends CharacterBody2D @onready var anim_player: AnimationPlayer = $AnimationPlayer func _physics_process(delta): var velocity = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") if velocity.length() > 0: if not anim_player.current_animation == "run": anim_player.play("run") else: if not anim_player.current_animation == "idle": anim_player.play("idle")
After (AnimationTree):
# player_animation.gd - State-driven animation extends CharacterBody2D @onready var animation_tree: AnimationTree = $AnimationTree @onready var playback: AnimationNodeStateMachinePlayback func _ready(): animation_tree.active = true playback = animation_tree.get("parameters/playback") func _physics_process(delta): var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") # Update blend position for BlendSpace2D animation_tree.set("parameters/blend_position", input_dir) # Transition states if input_dir.length() > 0.1: playback.travel("Locomotion") else: playback.travel("Idle")
Generated Scene:
# player.tscn [gd_scene load_steps=6 format=3] [ext_resource type="Script" path="res://player_animation.gd" id="1_abc123"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_idle"] animation = &"idle" [sub_resource type="AnimationNodeBlendSpace2D" id="AnimationNodeBlendSpace2D_loco"] blend_point_0/node = SubResource("AnimationNodeAnimation_idle") blend_point_0/pos = Vector2(0, 0) blend_point_1/node = SubResource("AnimationNodeAnimation_walk") blend_point_1/pos = Vector2(0, 1) blend_point_2/node = SubResource("AnimationNodeAnimation_run") blend_point_2/pos = Vector2(0, 1.5) [sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_main"] states/Idle/node = SubResource("AnimationNodeAnimation_idle") states/Idle/position = Vector2(300, 100) states/Locomotion/node = SubResource("AnimationNodeBlendSpace2D_loco") states/Locomotion/position = Vector2(500, 100) [sub_resource type="AnimationNodeStateMachinePlayback" id="AnimationNodeStateMachinePlayback_main"] [node name="Player" type="CharacterBody2D"] script = ExtResource("1_abc123") [node name="AnimationPlayer" type="AnimationPlayer" parent="."] [node name="AnimationTree" type="AnimationTree" parent="."] anim_player = NodePath("../AnimationPlayer") tree_root = SubResource("AnimationNodeStateMachine_main") parameters/playback = SubResource("AnimationNodeStateMachinePlayback_main") parameters/blend_position = Vector2(0, 0)
AnimationTree Activation
# Essential setup for AnimationTree func _ready(): # Activate the tree (must be done after node is ready) animation_tree.active = true # Get reference to state machine playback playback = animation_tree.get("parameters/playback") # Optional: Set initial state playback.start("Idle")
AnimationNodeStateMachine
State Machine Structure
State Machine Graph:
# State machine nodes in .tscn format [sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_character"] states/Start/position = Vector2(150, 100) states/End/position = Vector2(800, 100) # Idle state (single animation) states/Idle/node = SubResource("AnimationNodeAnimation_idle") states/Idle/position = Vector2(300, 100) # Locomotion (blend space) states/Locomotion/node = SubResource("AnimationNodeBlendSpace2D_loco") states/Locomotion/position = Vector2(500, 100) # Attack (one-shot animation) states/Attack/node = SubResource("AnimationNodeOneShot_attack") states/Attack/position = Vector2(500, 300) # Death state states/Death/node = SubResource("AnimationNodeAnimation_death") states/Death/position = Vector2(700, 100)
State Transitions
Transition Configuration:
# Transitions between states [sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_character"] # Idle -> Locomotion (auto on bool parameter) transitions = ["Idle", "Locomotion", SubResource("AnimationNodeStateMachineTransition_idle_to_loco")] # Locomotion -> Idle transitions = ["Locomotion", "Idle", SubResource("AnimationNodeStateMachineTransition_loco_to_idle")] # Any State -> Attack (using Attack trigger) transitions = ["Start", "Attack", SubResource("AnimationNodeStateMachineTransition_attack")] # Any State -> Death transitions = ["Start", "Death", SubResource("AnimationNodeStateMachineTransition_death")]
Transition Resource Definitions:
# Transition with condition var transition = AnimationNodeStateMachineTransition.new() transition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_IMMEDIATE transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO transition.advance_condition = "is_moving" # Transition with expression (Godot 4.1+) transition.advance_expression = "velocity.length() > 0.1" # Transition with time condition transition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END
Playback Control
# State machine playback script extends CharacterBody2D @onready var animation_tree: AnimationTree = $AnimationTree var playback: AnimationNodeStateMachinePlayback func _ready(): animation_tree.active = true playback = animation_tree.get("parameters/playback") func _physics_process(delta): # Transition to locomotion state if velocity.length() > 0.1: playback.travel("Locomotion") else: playback.travel("Idle") # Trigger attack (OneShot) if Input.is_action_just_pressed("attack"): playback.travel("Attack") # Trigger death (immediate) if health <= 0: playback.travel("Death") func stop_movement(): # Stop at current state playback.stop() func reset_to_idle(): # Start over from Start node playback.start("Idle")
BlendSpace2D Configuration
Locomotion Blend Space
Before (No Blending):
# Discrete animations - jarring transitions func update_animation(): if velocity.length() < 0.1: anim_player.play("idle") elif velocity.length() < 100: anim_player.play("walk") else: anim_player.play("run")
After (BlendSpace2D):
# Smooth blending between all animations func _physics_process(delta): # Normalize velocity for blend position (-1 to 1) var blend_pos = velocity / max_speed animation_tree.set("parameters/Locomotion/blend_position", blend_pos)
Generated BlendSpace2D:
# BlendSpace2D resource [sub_resource type="AnimationNodeBlendSpace2D" id="AnimationNodeBlendSpace2D_loco"] # Center - Idle blend_point_0/node = SubResource("AnimationNodeAnimation_idle") blend_point_0/pos = Vector2(0, 0) # Up - Walk North blend_point_1/node = SubResource("AnimationNodeAnimation_walk_north") blend_point_1/pos = Vector2(0, -1) # Down - Walk South blend_point_2/node = SubResource("AnimationNodeAnimation_walk_south") blend_point_2/pos = Vector2(0, 1) # Left - Walk West blend_point_3/node = SubResource("AnimationNodeAnimation_walk_west") blend_point_3/pos = Vector2(-1, 0) # Right - Walk East blend_point_4/node = SubResource("AnimationNodeAnimation_walk_east") blend_point_4/pos = Vector2(1, 0) # Diagonal blends (automatically interpolated) blend_point_5/node = SubResource("AnimationNodeAnimation_walk_northeast") blend_point_5/pos = Vector2(0.707, -0.707) # Blend mode blend_mode = 1 # BLEND_MODE_INTERPOLATED min_space = Vector2(-1.5, -1.5) max_space = Vector2(1.5, 1.5)
BlendSpace2D Setup Script
# Programmatically create BlendSpace2D func create_locomotion_blend_space() -> AnimationNodeBlendSpace2D: var blend_space = AnimationNodeBlendSpace2D.new() # Add idle animation at center var idle_node = AnimationNodeAnimation.new() idle_node.animation = "idle" blend_space.add_blend_point(idle_node, Vector2.ZERO) # Add directional walks var walk_north = AnimationNodeAnimation.new() walk_north.animation = "walk_north" blend_space.add_blend_point(walk_north, Vector2(0, -1)) var walk_south = AnimationNodeAnimation.new() walk_south.animation = "walk_south" blend_space.add_blend_point(walk_south, Vector2(0, 1)) var walk_east = AnimationNodeAnimation.new() walk_east.animation = "walk_east" blend_space.add_blend_point(walk_east, Vector2(1, 0)) var walk_west = AnimationNodeAnimation.new() walk_west.animation = "walk_west" blend_space.add_blend_point(walk_west, Vector2(-1, 0)) # Configure blend triangles for proper interpolation blend_space.add_triangle(0, 1, 4) # Idle, North, East blend_space.add_triangle(0, 4, 2) # Idle, East, South blend_space.add_triangle(0, 2, 3) # Idle, South, West blend_space.add_triangle(0, 3, 1) # Idle, West, North return blend_space
Parameter-Driven Blend Space
# Update blend space based on input/velocity func update_locomotion_blend(): var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down") # Calculate blend position based on input var blend_position = input_dir # Apply to AnimationTree animation_tree.set("parameters/Locomotion/blend_position", blend_position) # Also update speed scale for walk/run distinction var speed = velocity.length() var speed_scale = clamp(speed / base_speed, 0.5, 2.0) animation_tree.set("parameters/Locomotion/speed_scale", speed_scale)
BlendSpace3D Configuration
3D Locomotion Blend Space
# BlendSpace3D for 3D characters [sub_resource type="AnimationNodeBlendSpace3D" id="AnimationNodeBlendSpace3D_loco3d"] # Idle at center blend_point_0/node = SubResource("AnimationNodeAnimation_idle_3d") blend_point_0/pos = Vector3(0, 0, 0) # Cardinal directions blend_point_1/node = SubResource("AnimationNodeAnimation_walk_forward") blend_point_1/pos = Vector3(0, 0, 1) blend_point_2/node = SubResource("AnimationNodeAnimation_walk_backward") blend_point_2/pos = Vector3(0, 0, -1) blend_point_3/node = SubResource("AnimationNodeAnimation_strafe_left") blend_point_3/pos = Vector3(-1, 0, 0) blend_point_4/node = SubResource("AnimationNodeAnimation_strafe_right") blend_point_4/pos = Vector3(1, 0, 0) # Run variants at higher magnitude blend_point_5/node = SubResource("AnimationNodeAnimation_run_forward") blend_point_5/pos = Vector3(0, 0, 1.5)
3D Character Animation Script:
# character_3d.gd extends CharacterBody3D @onready var animation_tree: AnimationTree = $AnimationTree func _physics_process(delta): # Get local velocity relative to character rotation var local_velocity = transform.basis.inverse() * velocity # Normalize for blend position var blend_pos = Vector3( clamp(local_velocity.x / max_speed, -1, 1), 0, clamp(local_velocity.z / max_speed, -1, 1) ) # Update blend space animation_tree.set("parameters/Locomotion3D/blend_position", blend_pos) # Update animation speed based on actual velocity var speed_factor = velocity.length() / max_speed animation_tree.set("parameters/Locomotion3D/speed_scale", clamp(speed_factor, 0.5, 1.5))
State Transitions
Boolean Condition Transitions
# Setup boolean condition in AnimationTree func setup_conditions(): # Set condition values animation_tree.set("parameters/conditions/is_moving", velocity.length() > 0.1) animation_tree.set("parameters/conditions/is_attacking", Input.is_action_pressed("attack")) animation_tree.set("parameters/conditions/is_grounded", is_on_floor()) animation_tree.set("parameters/conditions/is_dead", health <= 0)
Corresponding Scene Configuration:
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_idle_to_move"] advance_mode = 1 # ADVANCE_MODE_AUTO advance_condition = "is_moving" [sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_move_to_idle"] advance_mode = 1 advance_condition = "is_moving" negated = true [sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_attack"] advance_mode = 1 advance_condition = "is_attacking"
Expression-Based Transitions
# Godot 4.1+ expression transitions # No need for manual condition setting # Transition expression examples: # "velocity.length() > 0.1" # "health <= 0" # "is_on_floor() and Input.is_action_pressed(\"jump\")" # "anim_time >= 0.8" (requires anim_time parameter tracking)
Setting up Expression Transitions:
func create_expression_transition(expression: String) -> AnimationNodeStateMachineTransition: var transition = AnimationNodeStateMachineTransition.new() transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO transition.advance_expression = expression return transition # Usage var jump_transition = create_expression_transition("is_on_floor() and Input.is_action_pressed('jump')") state_machine.add_transition("Idle", "Jump", jump_transition)
Time-Based Transitions
# Transition at end of animation var end_transition = AnimationNodeStateMachineTransition.new() end_transition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END end_transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO # Transition after specific time var time_transition = AnimationNodeStateMachineTransition.new() time_transition.switch_mode = AnimationNodeStateMachineTransition.SWITCH_MODE_AT_END time_transition.advance_mode = AnimationNodeStateMachineTransition.ADVANCE_MODE_AUTO # Add custom wait time via expression
Blend Trees
Complex Animation Mixing
OneShot for Actions:
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_attack"] animation = SubResource("AnimationNodeAnimation_attack") fadein_time = 0.1 fadeout_time = 0.15 mix_mode = 0 # ONE_SHOT_MIX_MODE_BLEND
Blend2 for Smooth Transitions:
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_action"]
Add2 for Layering:
[sub_resource type="AnimationNodeAdd2" id="AnimationNodeAdd2_recoil"] # Adds recoil on top of base animation
TimeScale for Speed Control:
[sub_resource type="AnimationNodeTimeScale" id="AnimationNodeTimeScale_run"] scale = 1.0 # Modified at runtime
Complete Blend Tree Example
# Complex blend tree with layering [sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_complex"] # Input animations nodes/Animation/node = SubResource("AnimationNodeAnimation_idle") nodes/Animation/position = Vector2(100, 100) # Time scale for speed control nodes/TimeScale/node = SubResource("AnimationNodeTimeScale_var") nodes/TimeScale/position = Vector2(300, 100) nodes/TimeScale/input_0 = SubResource("AnimationNodeAnimation_idle") # OneShot for hit reaction (layered on top) nodes/HitReaction/node = SubResource("AnimationNodeOneShot_hit") nodes/HitReaction/position = Vector2(500, 100) nodes/HitReaction/input_0 = SubResource("AnimationNodeTimeScale_var") # Add2 for weapon sway nodes/WeaponSway/node = SubResource("AnimationNodeAdd2_sway") nodes/WeaponSway/position = Vector2(700, 100) nodes/WeaponSway/input_0 = SubResource("AnimationNodeOneShot_hit") nodes/WeaponSway/input_1 = SubResource("AnimationNodeAnimation_sway") # Output nodes/Output/position = Vector2(900, 100) node_connections = [&"output", 0, &"WeaponSway"]
Blend Tree Script Control:
# Control blend tree parameters func update_blend_tree(): # Update time scale based on movement speed var speed = velocity.length() var time_scale = clamp(speed / base_speed, 0.5, 2.0) animation_tree.set("parameters/TimeScale/scale", time_scale) # Trigger OneShot if is_hit: animation_tree.set("parameters/HitReaction/active", true) animation_tree.set("parameters/HitReaction/internal_active", true) # Control Add2 amount (0.0 = no sway, 1.0 = full sway) var sway_amount = clamp(speed / max_speed, 0.0, 1.0) animation_tree.set("parameters/WeaponSway/add_amount", sway_amount)
Examples
2D Character Animation System
Complete Setup:
# character_animator.gd extends CharacterBody2D @onready var animation_tree: AnimationTree = $AnimationTree @onready var playback: AnimationNodeStateMachinePlayback @export var max_speed: float = 200.0 @export var blend_smoothness: float = 5.0 var target_blend_position: Vector2 = Vector2.ZERO var current_blend_position: Vector2 = Vector2.ZERO func _ready(): animation_tree.active = true playback = animation_tree.get("parameters/playback") func _physics_process(delta): # Get input var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down") # Calculate target blend position if input_dir.length() > 0.1: target_blend_position = input_dir playback.travel("Locomotion") else: target_blend_position = Vector2.ZERO playback.travel("Idle") # Smooth blend position transition current_blend_position = current_blend_position.lerp(target_blend_position, blend_smoothness * delta) animation_tree.set("parameters/Locomotion/blend_position", current_blend_position) # Handle actions if Input.is_action_just_pressed("attack"): playback.travel("Attack") if Input.is_action_just_pressed("interact"): playback.travel("Interact") func take_damage(): playback.travel("Hit") func die(): playback.travel("Death")
Generated Scene:
# animated_character.tscn [gd_scene load_steps=10 format=3] [ext_resource type="Script" path="res://character_animator.gd" id="1_anim123"] # Animation nodes [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_idle"] animation = &"idle" [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_attack"] animation = &"attack" [sub_resource type="AnimationNodeBlendSpace2D" id="AnimationNodeBlendSpace2D_loco"] blend_point_0/node = SubResource("AnimationNodeAnimation_idle") blend_point_0/pos = Vector2(0, 0) # ... more blend points # State machine [sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_main"] states/Start/position = Vector2(150, 100) states/Idle/node = SubResource("AnimationNodeAnimation_idle") states/Idle/position = Vector2(300, 100) states/Locomotion/node = SubResource("AnimationNodeBlendSpace2D_loco") states/Locomotion/position = Vector2(500, 100) states/Attack/node = SubResource("AnimationNodeAnimation_attack") states/Attack/position = Vector2(500, 300) states/End/position = Vector2(700, 100) # Transitions [sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_to_loco"] advance_condition = "is_moving" [sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_to_idle"] advance_condition = "is_moving" negated = true [node name="AnimatedCharacter" type="CharacterBody2D"] script = ExtResource("1_anim123") [node name="Sprite2D" type="Sprite2D" parent="."] [node name="AnimationPlayer" type="AnimationPlayer" parent="."] [node name="AnimationTree" type="AnimationTree" parent="."] anim_player = NodePath("../AnimationPlayer") tree_root = SubResource("AnimationNodeStateMachine_main") parameters/playback = SubResource("AnimationNodeStateMachinePlayback_main") parameters/Locomotion/blend_position = Vector2(0, 0) parameters/conditions/is_moving = false
Combat Animation System
Attack Combo System:
# combat_animator.gd extends CharacterBody2D @onready var animation_tree: AnimationTree = $AnimationTree @onready var playback: AnimationNodeStateMachinePlayback var combo_count: int = 0 var max_combo: int = 3 var combo_window: float = 0.5 var combo_timer: float = 0.0 func _ready(): animation_tree.active = true playback = animation_tree.get("parameters/playback") func _physics_process(delta): # Update combo timer if combo_timer > 0: combo_timer -= delta if combo_timer <= 0: combo_count = 0 # Handle attack input if Input.is_action_just_pressed("attack"): perform_attack() # Update animation conditions animation_tree.set("parameters/conditions/in_combo", combo_count > 0) func perform_attack(): match combo_count: 0: playback.travel("Attack1") 1: playback.travel("Attack2") 2: playback.travel("Attack3") _: combo_count = 0 playback.travel("Attack1") combo_count = (combo_count + 1) % max_combo combo_timer = combo_window func reset_combo(): combo_count = 0 combo_timer = 0.0
State Machine for Combos:
[sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_combat"] states/Idle/position = Vector2(300, 100) states/Attack1/position = Vector2(500, 100) states/Attack2/position = Vector2(500, 200) states/Attack3/position = Vector2(500, 300) # Attack1 -> Attack2 transition [sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_a1_a2"] switch_mode = 1 # SWITCH_MODE_AT_END advance_mode = 1 advance_condition = "in_combo" # Attack2 -> Attack3 transition [sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_a2_a3"] switch_mode = 1 advance_mode = 1 advance_condition = "in_combo" # All attacks -> Idle (when combo ends) [sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_end"] switch_mode = 1 advance_mode = 1 negated = true advance_condition = "in_combo"
NPC Animation with Random Idle Variations
# npc_animator.gd extends CharacterBody2D @onready var animation_tree: AnimationTree = $AnimationTree @onready var playback: AnimationNodeStateMachinePlayback var idle_variations: Array[String] = ["Idle", "Idle2", "Idle3"] var idle_timer: float = 0.0 var next_idle_change: float = 5.0 func _ready(): animation_tree.active = true playback = animation_tree.get("parameters/playback") pick_random_idle() func _physics_process(delta): # Random idle variation idle_timer += delta if idle_timer >= next_idle_change and velocity.length() < 0.1: idle_timer = 0.0 next_idle_change = randf_range(3.0, 8.0) pick_random_idle() # Movement if velocity.length() > 0.1: playback.travel("Walk") func pick_random_idle(): var random_idle = idle_variations[randi() % idle_variations.size()] playback.travel(random_idle)
Common Patterns
Animation Event Integration
# Connect animation events to gameplay func _ready(): animation_tree.animation_started.connect(_on_animation_started) animation_tree.animation_finished.connect(_on_animation_finished) func _on_animation_started(anim_name: StringName): match anim_name: "attack": # Disable movement during attack can_move = false "dash": # Make invincible is_invincible = true func _on_animation_finished(anim_name: StringName): match anim_name: "attack": can_move = true "dash": is_invincible = false
Animation-Driven Movement
# Root motion implementation func _on_animation_tree_animation_started(anim_name: StringName): if anim_name == &"attack": # Enable root motion tracking animation_tree.set("parameters/Attack/active", true) func _physics_process(delta): # Apply root motion from animation var root_motion: Transform3D = animation_tree.get_root_motion() global_transform *= root_motion
Smooth State Transitions
# Crossfade duration configuration var transition = AnimationNodeStateMachineTransition.new() transition.fade_duration = 0.2 # 200ms crossfade
Safety
- Always check if AnimationTree is active before accessing parameters
- Verify AnimationPlayer has all required animations before setting up tree
- Handle missing blend positions gracefully (default to center)
- Reset AnimationTree when reparenting or changing scenes
- Disconnect signals before queue_free()
When NOT to Use
Don't use AnimationTree when:
- Only 2-3 simple animations (overkill)
- Animation logic is extremely simple (just play/stop)
- Performance is critical on low-end devices
- You need direct frame-by-frame control
Use direct AnimationPlayer instead:
# Simple animation control func _physics_process(delta): if is_moving: anim_player.play("walk") else: anim_player.play("idle")
Integration
Works with:
- godot-add-signals - Connect animation events to gameplay systems
- godot-extract-to-scenes - Create reusable animated character scenes
- godot-setup-navigation - Navigation agents with movement animations
- godot-migrate-tilemap - Animated tilemap characters
Performance Tips
- Limit Blend Points - 4-8 points is usually enough
- Cache Parameters - Store parameter paths as constants
- Disable Unused Trees - Set
when off-screenactive = false - Use TimeScale - Instead of changing animation speeds
- Batch Transitions - Group state changes when possible