AnimationPlayer
2026/4/14大约 7 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — AnimationPlayer
AnimationPlayer
节点继承关系
继承链:Node -> AnimationMixer -> AnimationPlayer
继承自 Node
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Name | 节点名称 |
| 属性 | ProcessMode | 处理模式(始终 / 暂停时 / 仅编辑器) |
| 属性 | ProcessPriority | 处理优先级,数字越小越先执行 |
| 信号 | ready | 节点进入场景树并准备就绪 |
| 信号 | tree_entered | 节点进入场景树 |
| 信号 | tree_exited | 节点完全离开场景树 |
| 方法 | GetNode<T>() | 按路径获取子节点 |
| 方法 | AddChild() | 添加子节点 |
| 方法 | RemoveChild() | 移除子节点 |
| 方法 | QueueFree() | 帧结束后释放节点 |
| 方法 | GetParent() | 获取父节点 |
定义
AnimationPlayer 是 Godot 中最常用的属性动画播放器。它可以录制和播放任何节点的属性变化——位置、旋转、缩放、颜色、透明度、甚至调用方法。你只需要在编辑器里"录制"一串关键帧,它就能反复回放。
想象 AnimationPlayer 是一台录像机:你按下"录制"键,移动角色的手臂、改变按钮的颜色、调整门的开合角度,松开"录制"键后,这些操作就保存成了一段"录像"。以后你随时可以播放、暂停、倒放这段"录像"。
一句话理解:AnimationPlayer 负责录制和回放节点属性的变化序列,是 Godot 动画系统中最基础、最常用的节点。
使用频率:★★★★ 维度专用常用——几乎每个有动画的项目都会用到它。
节点用途
- 播放预先制作好的角色动作动画(走路、跑步、跳跃、攻击等)
- 控制 UI 元素的动画效果(按钮弹跳、面板淡入淡出、文字滚动等)
- 制作场景动画(开门、电梯升降、灯光闪烁等)
- 通过代码动态播放、暂停、切换动画
- 播放动画轨道上的音效和背景音乐
使用场景
典型场景
- 角色播放走路动画,松开方向键后切回待机动画
- 点击按钮时播放"按下去 -> 弹起来"的动画
- 场景中的门被打开后播放开门动画
- UI 面板从屏幕外滑入并淡入显示
不适用场景
- 需要根据角色状态自动切换多个动画(待机/走/跑/跳/攻击等) -> 配合 AnimationTree 使用
- 只需要做一次性的简单补间动画(比如物品飞向目标) -> 使用 Tween
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| AnimationTree | 作为 AnimationPlayer 的"高级遥控器",自动管理动作切换 | 角色动画推荐 |
| Skeleton2D | 2D 骨骼动画(Skeletal Animation)的载体,AnimationPlayer 驱动骨骼运动 | 2D 骨骼角色必需 |
| Skeleton3D | 3D 骨骼动画的载体,AnimationPlayer 驱动骨骼运动 | 3D 模型角色必需 |
| Sprite2D | 通过切换帧序列制作 2D 逐帧动画 | 2D 逐帧动画必需 |
| AudioStreamPlayer | 在动画轨道上同步播放音效 | 需要音效时 |
典型节点树结构:
CharacterBody2D (或 CharacterBody3D)
├── Sprite2D / MeshInstance3D ← 动画作用的目标节点
├── Skeleton2D / Skeleton3D ← 骨骼动画的目标节点
├── AnimationPlayer ← 播放动画
└── AnimationTree ← (可选)状态机管理生效必备素材/资源
| 资源 | 类型 | 说明 |
|---|---|---|
| Animation | Animation 资源 | 具体的动画数据,包含多条轨道和关键帧。在 AnimationPlayer 面板中创建 |
| AnimationLibrary | AnimationLibrary 资源 | 动画的容器,一个库可以包含多个 Animation。默认有一个空字符串命名的全局库 |
| SpriteFrames | SpriteFrames 资源 | 逐帧动画的帧序列数据(仅 Sprite2D 逐帧动画需要) |
支持的动画轨道类型
AnimationPlayer 支持在一条动画中混合使用多种轨道:
| 轨道类型 | 用途 | 示例 |
|---|---|---|
| 属性轨道(Property Track) | 修改节点属性 | 移动位置、旋转角度、改变颜色 |
| 方法轨道(Method Track) | 在指定时间调用方法 | 播放音效、发射粒子、触发事件 |
| 音频轨道(Audio Track) | 同步播放音频 | 脚步声随走路动画播放 |
| 动画轨道(Animation Track) | 嵌套播放另一个动画 | 在跑步动画中叠加呼吸动画 |
节点属性与信号
播放控制属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
CurrentAnimation | StringName | "" | — | 当前正在播放的动画名称。代码中通过此属性或 Play() 方法设置 |
AssignedAnimation | StringName | "" | — | 在编辑器中分配的动画名称,运行时会自动播放(除非被代码覆盖) |
SpeedScale | float | 1.0 | AnimationMixer | 播放速度倍率。2.0 表示两倍速,-1.0 表示倒放,0.5 表示慢放 |
Autoplay | StringName | "" | — | 场景加载后自动播放的动画名称。在编辑器的 AnimationPlayer 面板中设置 |
混合与过渡
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
BlendTimes | Dictionary | {} | — | 动画之间的过渡时间表。例如 {"Walk": 0.3, "Run": 0.2} 表示切到 Walk 动画时用 0.3 秒过渡 |
DefaultBlendTime | float | 0.0 | — | 默认过渡时间。当 BlendTimes 中没有为某对动画指定过渡时间时使用此值 |
信号
| 信号 | 参数 | 说明 |
|---|---|---|
AnimationFinished | animName: StringName | 动画播放完毕时触发。注意:循环动画不会触发此信号 |
AnimationStarted | animName: StringName | 动画开始播放时触发(包括从头播放和从队列中切换) |
AnimationChanged | oldName: StringName, newName: StringName | 当前动画被切换时触发,参数是新旧动画名称 |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
Play(name, customBlend, speed, fromEnd) | StringName | 播放指定动画。name 为空字符串则播放当前动画。返回实际播放的动画名 |
PlayBackwards(name) | StringName | 倒放指定动画 |
Pause() | void | 暂停当前动画 |
Stop() | void | 停止当前动画并重置到初始状态 |
Queue(name) | void | 将动画加入播放队列。当前动画播完后自动播放队列中的下一个 |
Seek(time, update) | void | 跳转到指定时间点(秒)。update 参数控制是否立即更新 |
GetCurrentAnimation() | StringName | 获取当前正在播放的动画名称 |
IsPlaying() | bool | 是否正在播放动画 |
GetQueue() | string[] | 获取当前播放队列中的动画列表 |
代码示例
播放走路动画,结束后切回待机
C
using Godot;
public partial class PlayerController : CharacterBody2D
{
private AnimationPlayer _animPlayer;
public override void _Ready()
{
_animPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
// 监听动画播放完毕的信号
_animPlayer.AnimationFinished += OnAnimationFinished;
}
public override void _PhysicsProcess(double delta)
{
Vector2 input = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
if (input != Vector2.Zero)
{
// 有输入时播放走路动画
_animPlayer.Play("Walk");
}
else
{
// 没有输入时播放待机动画
_animPlayer.Play("Idle");
}
}
/// <summary>
/// 动画播放完毕时的回调
/// </summary>
private void OnAnimationFinished(StringName animName)
{
// 攻击动画播完后自动回到待机
if (animName == "Attack")
{
_animPlayer.Play("Idle");
}
// 翻滚动画播完后回到待机
if (animName == "Roll")
{
_animPlayer.Play("Idle");
}
}
}GDScript
extends CharacterBody2D
@onready var anim_player: AnimationPlayer = $AnimationPlayer
func _ready():
# 监听动画播放完毕的信号
anim_player.animation_finished.connect(_on_animation_finished)
func _physics_process(_delta):
var input = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
if input != Vector2.ZERO:
# 有输入时播放走路动画
anim_player.play("Walk")
else:
# 没有输入时播放待机动画
anim_player.play("Idle")
## 动画播放完毕时的回调
func _on_animation_finished(anim_name: StringName):
# 攻击动画播完后自动回到待机
if anim_name == "Attack":
anim_player.play("Idle")
# 翻滚动画播完后回到待机
if anim_name == "Roll":
anim_player.play("Idle")使用队列和过渡
C
using Godot;
public partial class DoorController : Node
{
private AnimationPlayer _animPlayer;
public override void _Ready()
{
_animPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
// 设置默认过渡时间为 0.3 秒,让动画切换更平滑
_animPlayer.DefaultBlendTime = 0.3f;
// 设置特定动画之间的过渡时间
_animPlayer.BlendTimes = new Godot.Collections.Dictionary
{
{ "DoorOpen", 0.5f },
{ "DoorClose", 0.5f }
};
}
/// <summary>
/// 打开门:先播放把手旋转动画,然后播放门打开动画
/// </summary>
public void OpenDoor()
{
_animPlayer.Play("HandleTurn");
_animPlayer.Queue("DoorOpen");
}
/// <summary>
/// 调整播放速度
/// </summary>
public void SetAnimationSpeed(float speed)
{
_animPlayer.SpeedScale = speed;
}
}GDScript
extends Node
@onready var anim_player: AnimationPlayer = $AnimationPlayer
func _ready():
# 设置默认过渡时间为 0.3 秒,让动画切换更平滑
anim_player.default_blend_time = 0.3
# 设置特定动画之间的过渡时间
anim_player.blend_times = {
"DoorOpen": 0.5,
"DoorClose": 0.5
}
## 打开门:先播放把手旋转动画,然后播放门打开动画
func open_door():
anim_player.play("HandleTurn")
anim_player.queue("DoorOpen")
## 调整播放速度
func set_animation_speed(speed: float):
anim_player.speed_scale = speedAnimationPlayer vs AnimationTree
如果角色只有两三个动画(比如待机、走路、跳跃),直接用 AnimationPlayer 的 Play() 切换就够了。但如果角色有十几个动画并且需要根据速度、方向、状态自动混合切换,就应该加上 AnimationTree 来管理。
