12. 2D精灵与动画
2026/4/14大约 4 分钟
2D精灵与动画
游戏里的角色、敌人、道具看起来是"活的",靠的就是动画。本章讲怎么在 Godot 里做 2D 动画——从最简单的帧动画到高级的属性动画。
什么是"精灵"
精灵(Sprite)就是游戏里显示的一张图片。比如马里奥的角色图片、一个金币的图片、一棵树的图片,都是精灵。Godot 用 Sprite2D 节点来显示精灵。
AnimatedSprite2D —— 简单帧动画
最常用的动画方式。就像翻页动画书——快速切换不同的图片,看起来就像在动。
设置步骤
- 添加
AnimatedSprite2D节点到角色 - 在属性面板中创建
SpriteFrames资源 - 添加动画(如 "walk"、"jump"、"idle")
- 把对应的帧图片拖入每个动画
- 设置播放速度(FPS)
C#
// 根据移动状态切换动画
public void UpdateAnimation()
{
var animatedSprite = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
if (Velocity.X > 0)
{
animatedSprite.Play("walk");
animatedSprite.FlipH = false;
}
else if (Velocity.X < 0)
{
animatedSprite.Play("walk");
animatedSprite.FlipH = true;
}
else
{
animatedSprite.Play("idle");
}
}GDScript
# 根据移动状态切换动画
func update_animation():
if velocity.x > 0:
$AnimatedSprite2D.play("walk")
$AnimatedSprite2D.flip_h = false
elif velocity.x < 0:
$AnimatedSprite2D.play("walk")
$AnimatedSprite2D.flip_h = true
else:
$AnimatedSprite2D.play("idle")精灵图集(SpriteSheet)
把一个角色的所有帧拼到一张大图上,比一张一张的小图更高效:
- 在 Godot 中选中精灵图集图片
- 导入设置选择 2D Animation → 精灵帧
- 设置网格大小(如 32×32)
- 在 AnimatedSprite2D 中逐帧选择对应区域
提示
使用精灵图集的好处:减少文件数量、加载更快、GPU 只需加载一张纹理。
AnimationPlayer —— 高级动画
AnimationPlayer 不仅能切换图片帧,还能:
- 移动节点位置
- 改变节点大小
- 修改透明度
- 调用函数
- 控制任意节点的任意属性
创建动画
- 添加
AnimationPlayer节点到场景 - 点击"动画"按钮 → "新建动画"
- 在时间轴上添加关键帧
- 调整各关键帧的属性值
C#
// 播放动画
GetNode<AnimationPlayer>("AnimationPlayer").Play("explode");
// 播放动画并等待完成
await ToSignal(GetNode<AnimationPlayer>("AnimationPlayer"),
AnimationPlayer.SignalName.AnimationFinished);
// 动画完成后执行逻辑
QueueFree();GDScript
# 播放动画
$AnimationPlayer.play("explode")
# 播放动画并等待完成
await $AnimationPlayer.animation_finished
# 动画完成后执行逻辑
queue_free()AnimationPlayer 做爆炸效果
C#
// 爆炸动画(缩放 + 透明度)
// 在 AnimationPlayer 编辑器中设置:
// 0.0s: scale = (1, 1), modulate:a = 1.0
// 0.3s: scale = (2, 2), modulate:a = 0.0
// 然后在代码中播放
public void Explode()
{
var animPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
animPlayer.Play("explode");
// 动画结束后删除节点
animPlayer.AnimationFinished += () => QueueFree();
}GDScript
# 爆炸动画(缩放 + 透明度)
# 在 AnimationPlayer 编辑器中设置:
# 0.0s: scale = (1, 1), modulate:a = 1.0
# 0.3s: scale = (2, 2), modulate:a = 0.0
# 然后在代码中播放
func explode():
var anim_player = $AnimationPlayer
anim_player.play("explode")
# 动画结束后删除节点
await anim_player.animation_finished
queue_free()Tween —— 代码动画
Tween(补间动画)用代码直接控制动画,不需要在编辑器里预先制作。适合做一次性的平滑过渡效果。
常用场景
| 场景 | 效果 | Tween 方法 |
|---|---|---|
| 金币拾取 | 金币飞向 HUD | tween_property 移动 |
| 受伤闪烁 | 角色闪烁变透明 | tween_property 透明度 |
| 按钮 hover | 放大缩小 | tween_property 缩放 |
| 文字弹出 | 分数飘上去消失 | tween_property + 回调 |
受伤闪烁效果
C#
public void TakeDamage(int amount)
{
Hp -= amount;
var tween = CreateTween();
var sprite = GetNode<Sprite2D>("Sprite2D");
for (int i = 0; i < 5; i++)
{
tween.TweenProperty(sprite, "modulate:a", 0.3, 0.05);
tween.TweenProperty(sprite, "modulate:a", 1.0, 0.05);
}
}GDScript
func take_damage(amount):
hp -= amount
var tween = create_tween()
for i in range(5):
tween.tween_property($Sprite2D, "modulate:a", 0.3, 0.05)
tween.tween_property($Sprite2D, "modulate:a", 1.0, 0.05)金币拾取飘字
C#
public void CollectCoin(Vector2 coinPosition)
{
var popupScene = GD.Load<PackedScene>("res://hud/score_popup.tscn");
var popup = popupScene.Instantiate<Node2D>();
popup.Position = coinPosition;
AddChild(popup);
var tween = CreateTween();
tween.TweenProperty(popup, "position:y", coinPosition.Y - 40, 0.5);
tween.TweenProperty(popup, "modulate:a", 0.0, 0.5);
tween.TweenCallback(Callable.From(popup.QueueFree));
}GDScript
func collect_coin(coin_position: Vector2):
var popup = preload("res://hud/score_popup.tscn").instantiate()
popup.position = coin_position
add_child(popup)
var tween = create_tween()
tween.tween_property(popup, "position:y", coin_position.y - 40, 0.5)
tween.tween_property(popup, "modulate:a", 0.0, 0.5)
tween.tween_callback(popup.queue_free)平滑移动到目标位置
C#
// 让敌人被击退
public void Knockback(Vector2 direction, float force)
{
var tween = CreateTween();
tween.SetEase(Tween.EaseType.Out);
tween.SetTrans(Tween.TransitionType.Quad);
var targetPos = Position + direction * force;
tween.TweenProperty(this, "position", targetPos, 0.3);
}GDScript
# 让敌人被击退
func knockback(direction: Vector2, force: float):
var tween = create_tween()
tween.set ease(Tween.EASE_OUT)
tween.set_trans(Tween.TRANS_QUAD)
var target_pos = position + direction * force
tween.tween_property(self, "position", target_pos, 0.3)选择合适的动画方式
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| AnimatedSprite2D | 角色行走、跳跃、攻击等帧动画 | 简单直观,编辑器可视化 | 只能切换帧 |
| AnimationPlayer | 复杂的属性动画(缩放、移动、透明度、调用函数) | 功能强大,精确控制 | 需要编辑器预制作 |
| Tween | 一次性平滑过渡(受伤闪烁、物品飘动) | 纯代码,灵活 | 不适合循环动画 |
提示
大多数情况下,角色动画用 AnimatedSprite2D,UI 和特效动画用 Tween,复杂的过场动画用 AnimationPlayer。
下一章
动画搞定了,接下来加入音频、粒子特效,让游戏更有表现力。
