AnimatedSprite2D
2026/4/14大约 4 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — AnimatedSprite2D
AnimatedSprite2D
节点继承关系
继承链:Node → Node2D → CanvasItem → AnimatedSprite2D
定义
AnimatedSprite2D 专门播放帧动画——快速切换一系列图片,看起来就像"动起来了"。和 Sprite2D 只能显示一张图不同,它可以管理多组动画(走路、跳跃、攻击等)并随时切换。你只需要把动画帧图片配好,剩下的播放控制它全包了。
一句话理解:Sprite2D 是一张照片,AnimatedSprite2D 是一段 GIF 动图。
使用频率:★★★★ 维度专用常用——2D 游戏中角色动画的首选节点。
节点用途
- 管理多组动画(idle、walk、run、jump、attack、hurt、die 等)
- 自动播放或手动控制动画切换
- 通过信号监听动画完成事件(如攻击动画播完切回待机)
- 调整播放速度实现慢动作或加速效果
使用场景
| 场景 | 说明 |
|---|---|
| 角色动画 | 管理角色的所有动作动画组 |
| 怪物/NPC 动画 | 敌人和 NPC 的各种状态动画 |
| 物品动画 | 宝箱开启、金币旋转等 |
| 特效动画 | 爆炸、烟雾、闪光等一次性动画 |
常用节点搭配
| 搭配节点 | 搭配方式 | 用途 |
|---|---|---|
CollisionShape2D | 作为兄弟子节点 | 给动画角色加上碰撞体 |
AnimationPlayer | 作为兄弟子节点 | 处理节点属性动画(如位置移动)与精灵帧动画配合 |
StateMachine(自定义) | 作为父节点或兄弟 | 实现动画状态机(Animation State Machine),根据角色状态自动切换动画 |
AudioStreamPlayer2D | 作为兄弟子节点 | 播放动画对应的音效(如攻击音效) |
生效必备素材/资源
| 资源类型 | 格式 | 说明 |
|---|---|---|
SpriteFrames | .tres / .res | 核心资源!存放所有动画组及其帧图片。在编辑器中通过底部面板配置 |
Texture2D | .png、.webp | 每一帧的图片资源,嵌入到 SpriteFrames 中 |
节点属性与信号
动画控制属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
SpriteFrames | SpriteFrames | null | — | 动画资源,存放所有动画组和帧图片 |
Animation | StringName | &"" | — | 当前播放的动画名称 |
Frame | int | 0 | — | 当前帧索引 |
SpeedScale | float | 1.0 | — | 播放速度倍率。2.0 = 两倍速,0.5 = 半速 |
Autoplay | StringName | &"" | — | 场景加载后自动播放的动画名。设为 "idle" 就会自动播放待机动画 |
继承自 CanvasItem 的常用属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
SelfModulate | Color | Color(1, 1, 1, 1) | CanvasItem | 修改节点颜色(受伤闪红、死亡变灰) |
Visible | bool | true | CanvasItem | 是否可见 |
FlipH | bool | false | CanvasItem | 水平翻转(角色朝向) |
FlipV | bool | false | CanvasItem | 垂直翻转 |
信号
| 信号 | 参数 | 触发时机 |
|---|---|---|
AnimationFinished | 无 | 当前动画播放完毕(仅在非循环动画时触发) |
AnimationFrameChanged | animation: StringName, frame: int | 帧切换时触发,可用于帧同步逻辑 |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
Play(name, customSpeed, fromEnd) | void | 播放指定动画。name 为动画名,customSpeed 可覆盖速度 |
Pause() | void | 暂停当前动画 |
Stop() | void | 停止动画并回到第一帧 |
IsPlaying() | bool | 当前是否正在播放动画 |
代码示例
基础用法:播放和切换动画
C
var anim = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
// 播放"走路"动画
anim.Play("walk");
// 切换到"攻击"动画
anim.Play("attack");
// 暂停动画
anim.Pause();
// 停止动画
anim.Stop();
// 检查是否正在播放
if (anim.IsPlaying())
{
GD.Print("动画正在播放中");
}GDScript
var anim = $AnimatedSprite2D
# 播放"走路"动画
anim.play("walk")
# 切换到"攻击"动画
anim.play("attack")
# 暂停动画
anim.pause()
# 停止动画
anim.stop()
# 检查是否正在播放
if anim.is_playing():
print("动画正在播放中")动画播放完毕回调
C
var anim = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
// 攻击动画播完后自动切回待机
anim.AnimationFinished += () =>
{
GD.Print("动画播完了!");
anim.Play("idle");
};GDScript
var anim = $AnimatedSprite2D
# 攻击动画播完后自动切回待机
anim.animation_finished.connect(func():
print("动画播完了!")
anim.play("idle")
)角色动画状态机(简化版)
C
public partial class Player : CharacterBody2D
{
private AnimatedSprite2D _anim;
public override void _Ready()
{
_anim = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
// 攻击动画播完后回到待机
_anim.AnimationFinished += () =>
{
if (_anim.Animation == "attack")
{
_anim.Play("idle");
}
};
}
public override void _PhysicsProcess(double delta)
{
var velocity = Vector2.Zero;
// 获取输入方向
if (Input.IsActionPressed("move_right"))
velocity.X += 1;
if (Input.IsActionPressed("move_left"))
velocity.X -= 1;
// 根据移动状态切换动画
if (velocity.X != 0)
{
_anim.Play("walk");
_anim.FlipH = velocity.X < 0; // 朝向
}
else if (Input.IsActionJustPressed("attack"))
{
_anim.Play("attack");
}
else
{
_anim.Play("idle");
}
}
}GDScript
extends CharacterBody2D
@onready var _anim: AnimatedSprite2D = $AnimatedSprite2D
func _ready():
# 攻击动画播完后回到待机
_anim.animation_finished.connect(func():
if _anim.animation == "attack":
_anim.play("idle")
)
func _physics_process(delta):
var velocity = Vector2.ZERO
# 获取输入方向
if Input.is_action_pressed("move_right"):
velocity.x += 1
if Input.is_action_pressed("move_left"):
velocity.x -= 1
# 根据移动状态切换动画
if velocity.x != 0:
_anim.play("walk")
_anim.flip_h = velocity.x < 0 # 朝向
elif Input.is_action_just_pressed("attack"):
_anim.play("attack")
else:
_anim.play("idle")