AnimationTree
最后同步日期:2026-04-15 | Godot 官方原文 — AnimationTree
AnimationTree
节点继承关系
继承链:Node -> AnimationMixer -> AnimationTree
继承自 Node
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Name | 节点名称 |
| 属性 | ProcessMode | 处理模式(始终 / 暂停时 / 仅编辑器) |
| 属性 | ProcessPriority | 处理优先级,数字越小越先执行 |
| 信号 | ready | 节点进入场景树并准备就绪 |
| 信号 | tree_entered | 节点进入场景树 |
| 信号 | tree_exited | 节点完全离开场景树 |
| 方法 | GetNode<T>() | 按路径获取子节点 |
| 方法 | AddChild() | 添加子节点 |
| 方法 | RemoveChild() | 移除子节点 |
| 方法 | QueueFree() | 帧结束后释放节点 |
| 方法 | GetParent() | 获取父节点 |
定义
AnimationTree 是 Godot 中的高级动画状态机(Animation State Machine)。它不能独立工作,必须配合 AnimationPlayer 使用。它的作用是让角色在多个动画之间自动、平滑地切换——比如角色从待机到走路、从走路到跑步、从任何状态切换到攻击,全部自动完成,不需要你手动写一堆 if-else 来切换动画。
想象 AnimationTree 是一个片场导演:AnimationPlayer 是"演员"(负责表演每个动作),而 AnimationTree 是"导演"(根据现场情况指挥演员"现在从走路切到跑步"、"把走路和跑步混合 50% 显示")。你只需要告诉导演"角色移动速度是多少",导演就会自动决定该播放什么动画、混合比例是多少。
一句话理解:AnimationTree 是 AnimationPlayer 的"智能遥控器",能根据参数自动混合和切换动画,特别适合角色有大量动作状态的游戏。
使用频率:★★★★ 常用——角色动作丰富的游戏几乎必备,简单的 UI 动画则不需要。
节点用途
- 根据角色移动速度自动混合"待机 -> 走路 -> 跑步"动画
- 管理角色状态机(待机、移动、跳跃、攻击、受伤、死亡等状态之间的切换)
- 实现动画的平滑过渡和混合(比如上半身攻击、下半身走路的"分层动画")
- 通过代码参数实时控制动画行为(速度、方向、是否在地面等)
使用场景
典型场景
- 3D/2D 角色有多种动作状态,需要根据输入和物理状态自动切换
- 需要"上半身攻击 + 下半身走路"这种分层混合动画
- 角色从任何状态都能随时切换到攻击或受伤状态
- 根据移动速度平滑混合待机和走路动画
不适用场景
- 只有两三个简单动画,手动用
Play()切换就够了 -> 直接用 AnimationPlayer - UI 动画、门开关等非角色动画 -> 用 AnimationPlayer
- 一次性补间效果 -> 用 Tween
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| AnimationPlayer | 提供动画资源供 AnimationTree 使用 | 必需 |
| Skeleton2D | 2D 骨骼动画(Skeletal Animation)的载体 | 2D 骨骼角色必需 |
| Skeleton3D | 3D 骨骼动画的载体 | 3D 模型角色必需 |
| AnimationNodeStateMachine | 状态机根节点(在资源中配置) | 最常用的模式 |
| AnimationNodeBlendTree | 混合树根节点(在资源中配置) | 分层动画时使用 |
典型节点树结构:
CharacterBody3D
├── MeshInstance3D ← 3D 模型
├── Skeleton3D ← 骨骼
├── AnimationPlayer ← 存储所有动画资源
│ └── (包含 Idle, Walk, Run, Attack, Jump, Die 等动画)
└── AnimationTree ← 状态机,引用上面的 AnimationPlayer
└── (TreeRoot 资源中配置状态机)AnimationTree 内部的状态机结构(示意):
AnimationNodeStateMachine (根节点)
├── State: Idle(待机)
├── State: Walk(走路)
├── State: Run(跑步)
├── State: Jump(跳跃)
├── State: Attack(攻击)
└── State: Die(死亡)
(各状态之间通过 Transition 连接,设置切换条件)生效必备素材/资源
| 资源 | 类型 | 说明 |
|---|---|---|
| AnimationPlayer | 场景节点 | AnimationTree 必须引用一个 AnimationPlayer 来获取动画资源 |
| AnimationNode(TreeRoot) | AnimationNode 资源 | 状态机或混合树的根节点资源,在编辑器中可视化编辑 |
| Animation | Animation 资源 | 各个具体动画,存储在引用的 AnimationPlayer 中 |
节点属性与信号
基础属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
Active | bool | false | — | 是否激活。必须设为 true 才会生效,默认是关闭的 |
AnimPlayer | NodePath | "" | — | 引用的 AnimationPlayer 节点路径。必须正确设置,否则 AnimationTree 无法获取动画 |
TreeRoot | AnimationNode | null | — | 状态机/混合树的根节点资源。在编辑器中点击此属性可打开可视化编辑器 |
ProcessCallback | 枚举 | Idle | AnimationMixer | 更新时机:Idle(渲染帧)/ Physics(物理帧)/ Manual(手动) |
高级属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
RootMotionTrack | NodePath | "" | AnimationMixer | 根运动轨道路径,用于从动画中提取位移数据驱动角色移动 |
RootMotionLocal | bool | false | AnimationMixer | 根运动是否使用本地坐标系 |
信号
| 信号 | 参数 | 说明 |
|---|---|---|
AnimationStarted | animName: StringName | 动画开始播放时触发 |
AnimationFinished | animName: StringName | 动画播放完毕时触发(循环动画不触发) |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
Set(parameter, value) | void | 设置状态机参数。最常用的方法,用于从代码中控制状态机行为 |
Get(parameter) | Variant | 获取状态机参数的值 |
Travel(stateName) | void | 让状态机从当前状态切换到指定状态 |
Advance(delta) | void | 手动推进动画(配合 Manual 模式使用) |
代码示例
通过代码控制动画状态机
using Godot;
public partial class CharacterAnimation : CharacterBody3D
{
private AnimationTree _animTree;
public override void _Ready()
{
_animTree = GetNode<AnimationTree>("AnimationTree");
// 激活 AnimationTree(默认是关闭的!)
_animTree.Active = true;
}
public override void _PhysicsProcess(double delta)
{
Vector2 inputDir = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
Vector3 velocity = Velocity;
// 计算水平移动速度
Vector3 flatVelocity = new Vector3(velocity.X, 0, velocity.Z);
float speed = flatVelocity.Length();
// 根据速度更新状态机参数
// "parameters/Speed/blend_amount" 对应 BlendSpace 中的速度轴
_animTree.Set("parameters/Speed/blend_amount", speed);
// 根据输入方向更新朝向参数
if (inputDir != Vector2.Zero)
{
_animTree.Set("parameters/Direction/blend_position", inputDir);
}
// 触发攻击状态
if (Input.IsActionJustPressed("attack"))
{
// Travel 让状态机跳转到 Attack 状态
_animTree.Travel("Attack");
// 或者通过触发条件参数来切换
// _animTree.Set("parameters/conditions/attack", true);
}
// 触发跳跃状态
if (Input.IsActionJustPressed("jump") && IsOnFloor())
{
_animTree.Travel("Jump");
}
}
}extends CharacterBody3D
@onready var anim_tree: AnimationTree = $AnimationTree
func _ready():
# 激活 AnimationTree(默认是关闭的!)
anim_tree.active = true
func _physics_process(_delta):
var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
var velocity = Velocity
# 计算水平移动速度
var flat_velocity = Vector3(velocity.x, 0, velocity.z)
var speed = flat_velocity.length()
# 根据速度更新状态机参数
# "parameters/Speed/blend_amount" 对应 BlendSpace 中的速度轴
anim_tree["parameters/Speed/blend_amount"] = speed
# 根据输入方向更新朝向参数
if input_dir != Vector2.ZERO:
anim_tree["parameters/Direction/blend_position"] = input_dir
# 触发攻击状态
if Input.is_action_just_pressed("attack"):
# Travel 让状态机跳转到 Attack 状态
anim_tree.travel("Attack")
# 或者通过触发条件参数来切换
# anim_tree["parameters/conditions/attack"] = true
# 触发跳跃状态
if Input.is_action_just_pressed("jump") and is_on_floor():
anim_tree.travel("Jump")别忘了激活!
AnimationTree 的 Active 属性默认是 false,如果你在代码或编辑器中没有把它设为 true,所有动画都不会播放。这是新手最常踩的坑之一。
参数路径怎么写?
AnimationTree 的参数路径格式是 "parameters/参数名/子属性名"。例如:
"parameters/Speed/blend_amount"—— 速度混合量"parameters/conditions/attack"—— 攻击条件开关"parameters/Idle/blend_amount"—— Idle 状态的混合量
具体路径取决于你在 AnimationTree 编辑器中创建的节点名称。
