Animation — AnimationPlayer and AnimationTree
AnimationLibrary, state machine, blend spaces, root motion.
AnimationPlayer — the main node
AnimationPlayer holds an AnimationLibrary with a set of Animation resources and plays them.
A unique Godot feature — you can animate any property of any node (or even a
resource), not just Transform and Material:
- Transform (position, rotation, scale)
- Any property (sprite alpha,
visible, numbers, colors) - Shader uniforms — via the property path
material:shader_parameter/threshold - Method calls (call a function on a timer in a track)
- Audio (start an AudioStreamPlayer)
- Nested animations of other AnimationPlayers
Player (Node3D)
├── Skeleton3D
│ └── MeshInstance3D
└── AnimationPlayer ← all clips here: Idle, Run, Jump, Attack
$AnimationPlayer.play("Run")
$AnimationPlayer.play("Jump", -1, 1.2) # blend_time=-1, speed=1.2
$AnimationPlayer.speed_scale = 0.5 # all clips slowed to half speed
$AnimationPlayer.stop()
$AnimationPlayer.seek(0.5, true) # jump to 0.5 s
# End-of-animation signal
$AnimationPlayer.animation_finished.connect(_on_anim_done)
A GSAP / Framer Motion timeline: you describe tracks on element properties with keyframes, and time drives the animation.
The Unity Animation Window has the same feel of recording tracks along a timeline. But the Unity Animator Controller is a separate state-machine asset. In Godot its equivalent is AnimationTree, and it’s bound to a single AnimationPlayer.
Recording animation in the editor
- Select the AnimationPlayer in the scene → the Animation editor appears at the bottom.
- The “Animation” button → New → a name.
- Enable the red dot (Recording) → change any property in the Inspector → a keyframe is created automatically at the current point on the timeline.
- Scrub the timeline → change it again → a second keyframe.
Tracks can also be added manually via “Add Track”.
AnimationTree — state machine and blend space
For complex animation (locomotion, transitions), use AnimationTree — a separate node that reads animations from the linked AnimationPlayer and processes them through a node graph:
Player (Node3D)
├── AnimationPlayer
└── AnimationTree ← root: AnimationNodeStateMachine
tree_root points to the root graph
anim_player points to the AnimationPlayer
The root graph of an AnimationTree is an AnimationNode. Types:
- AnimationNodeStateMachine — an FSM with states and transitions.
- AnimationNodeBlendTree — a graph for blending.
- AnimationNodeBlendSpace1D — 1D parametric blending (for example,
speed0..6 ↔ Idle ↔ Walk ↔ Run). - AnimationNodeBlendSpace2D — 2D (for example,
strafe_x,forward_yfor 8-directional movement). - AnimationNodeAdd2/3 — additive pose blending.
- AnimationNodeOneShot — a single playback on top (for example, a “shoot” over a walk).
- AnimationNodeTimeScale / TimeSeek.
States via StateMachine
@onready var anim_tree: AnimationTree = $AnimationTree
@onready var state_machine = anim_tree["parameters/playback"] # AnimationNodeStateMachinePlayback
func _ready() -> void:
anim_tree.active = true
func _process(delta: float) -> void:
var speed = velocity.length()
anim_tree["parameters/Move/blend_position"] = speed # 1D blend space
if Input.is_action_just_pressed("jump"):
state_machine.travel("Jump") # smart transition through the graph (A* path finding)
travel("StateName") is the headline feature of Godot’s StateMachine: it finds a short path through
the transitions. Want to go from Idle to Land? If there’s no direct arrow, Godot will find Idle → Run → Land and traverse it.
AnimationTree exposes all of the graph’s configurable parameters via string subscript notation.
anim_tree["parameters/Locomotion/blend_position"] is a path in the graph. For frequent access,
you can cache the path in a var path = "parameters/...": constant.
Root Motion
If the skeleton moves in the animation (“a step forward”), by default the AnimationPlayer does not move the GameObject. It only changes poses. To translate the skeleton’s displacement into actual node movement:
- On the AnimationTree, set
root_motion_track— the path to the root bone (Skeleton3D:Hips). - In the script, read
anim_tree.get_root_motion_position()and apply it to the node:
func _physics_process(delta: float) -> void:
var motion = anim_tree.get_root_motion_position()
velocity = transform.basis * motion / delta
move_and_slide()
When not to use root motion: classic FPS games/platformers where speed is computed by logic. It’s used for cinematic movements, grapples, and finishers.
Skeleton3D, Bones, Bone Attachment
Skeleton3D is a hierarchy of bones. It’s applied to the skinning of a MeshInstance3D via a Skin resource.
BoneAttachment3D is a node that follows a bone. You attach weapons and accessories to it:
Player
├── Skeleton3D
│ ├── MeshInstance3D (skinned)
│ └── BoneAttachment3D (bone_name = "RightHand")
│ └── Sword (Node3D + MeshInstance3D)
IK — Inverse Kinematics
In 4.6, IK returned in the form of solver nodes inside Skeleton3D (nodes inheriting from SkeletonModifier3D):
- TwoBoneIK3D — two links (an arm/leg) with a target position.
- FABRIK3D — Forward And Backward Reaching IK (multiple links).
- CCDIK3D — Cyclic Coordinate Descent.
- ChainIK3D, SplineIK3D, JacobianIK3D, IterateIK3D — additional solvers for special cases.
Applied via SkeletonModifier3D nodes attached to Skeleton3D. Example: a character’s hand
reaches for a door handle during interaction.
Importing animation
Sources:
- glTF 2.0 — the recommended format for 3D models with animation. It exports perfectly from Blender.
- FBX — native import since 4.3 via ufbx (no external FBX2glTF).
- Mixamo animations — better via glTF; FBX also works with retargeting.
On import, Godot creates a scene (a .tscn equivalent) with Skeleton3D + AnimationPlayer + AnimationLibrary.
Import settings (scale factor, animation library mapping) are in the Import dock.
For retargeting (transferring an animation from one skeleton to another), use a Skeleton Profile (SkeletonProfileHumanoid is built in).
Animation Events / Method Tracks
The Godot equivalent of a Unity Animation Event is a Method Track: a track that calls a method on a node at a given moment. In the Animation editor: Add Track → Call Method Track → select a node → a keyframe stores the method name and parameters in its payload:
# This method can be triggered from a Method Track in the "Walk" animation
func on_footstep() -> void:
$StepSound.play()
In the next chapter — UI.