2D 精灵动画

前言

在本教程中,你将学习如何使用 AnimatedSprite2D 类和 AnimationPlayer 创建 2D 动画角色。 通常,当你创建或下载动画角色时,它将以两种方式之一出现:作为单独的图像或作为包含所有动画帧的单个精灵表。 两者都可以在 Godot 中使用 AnimatedSprite2D 类进行动画处理。

首先,我们将使用 AnimatedSprite2D 对单个图像集合进行动画处理。 然后我们将使用此类对精灵表进行动画处理。 最后,我们将学习另一种使用 AnimationPlayerSprite2DAnimation 属性来制作精灵表动画的方法。

备注

以下示例的美术资产由 https://opengameart.org/users/ansimuzhttps://opengameart.org/users/tgfcoder 共同提供。

AnimateSprite2D 与若干单独的图片

在这个情况下,你有一组图像,每一个都包含你角色的动画的一帧。 对于这个例子,我们将使用以下动画:

../../_images/2d_animation_run_preview.gif

你可以在这里下载图片:2d_sprite_animation_assets.zip

解压缩这些图像并将它们放在项目文件夹中。 使用以下节点布置场景树:

../../_images/2d_animation_tree1.webp

备注

根节点也可以是 Area2DRigidBody2D。动画仍然会以同样的方式制作。一旦动画完成,你就可以为 CollisionShape2D 形状分配一个形状。更多信息请参见物理介绍

现在选中 AnimatedSprite2D ,并在它的 SpriteFrames 属性中,选择“新建 SpriteFrames”。

../../_images/2d_animation_new_spriteframes.webp

点击新的 SpriteFrames 资源,你会看到一个新的面板出现在编辑器窗口的底部:

../../_images/2d_animation_spriteframes.webp

将这 8 张独立的图片从左边的“文件系统”面板拖放到“动画帧”面板的中间部分。在左边,将动画名称从“default”更改为“run”。

../../_images/2d_animation_spriteframes_done.webp

使用 过滤动画(Filter Animations) 输入右上角的“播放(Play)”按钮预览动画。 你现在应该可以看到动画在视口中播放。 然而,它有点慢。 要解决此问题,请将 SpriteFrames 面板中的 Speed (FPS) 设置更改为 10。

你可以通过单击“添加动画”按钮并添加其他图像来添加其他动画。

控制动画

动画完成后,你可以通过代码中的 play()stop() 方法控制动画。 这里有一个简单的例子,按住右方向键播放动画,松开后就停下。

extends CharacterBody2D

@onready var _animated_sprite = $AnimatedSprite2D

func _process(_delta):
    if Input.is_action_pressed("ui_right"):
        _animated_sprite.play("run")
    else:
        _animated_sprite.stop()

AnimateSprite2D 与精灵表

你还可以很方便地使用 AnimatedSprite2D 把精灵表做成动画。我们会用到这张公共领域的精灵表:

../../_images/2d_animation_frog_spritesheet.png

右键单击图片,选择“图片另存为”来下载图片,然后将图片复制到项目文件夹中。

设置场景树的方法与之前使用单独图片的时候相同。选中 AnimatedSprite2D 后在 SpriteFrames 属性里选择“新建 SpriteFrames”。

点击创建出来的 SpriteFrames 资源。底部面板出现后,这次我们选择“从精灵表中添加帧”。

../../_images/2d_animation_add_from_spritesheet.webp

在弹出的打开文件对话框中,选择你的精灵表。

接下来会打开一个新的窗口,里面会显示刚才的精灵表。你首先需要修改精灵表中纵向和横向的图片数量,我们的这张精灵表里横向有四张图片、纵向有两张。

../../_images/2d_animation_spritesheet_select_rows.webp

然后,在精灵表中选择动画中想要包含的帧。这里我们选中上面的四个,然后点击“添加 4 帧”来创建动画。

../../_images/2d_animation_spritesheet_selectframes.webp

现在你就可以看到在底部面板的动画列表里看到这个动画了。双击 default(默认),然后把动画的名称改成 jump(跳跃)。

../../_images/2d_animation_spritesheet_animation.webp

最后,点击 SpriteFrames 编辑器上的播放按钮,你的青蛙就能跳起来了!

../../_images/2d_animation_play_spritesheet_animation.webp

AnimationPlayer 与精灵表

使用 Sprite Sheet 时制作动画的另一种方法是使用标准 Sprite2D 节点来显示纹理,然后使用 AnimationPlayer 对纹理之间的变化进行动画处理 。

考虑一下这个包含 6 帧动画的精灵表:

../../_images/2d_animation_player-run.png

右键单击图片,选择“图片另存为”下载图片,然后将图片复制到项目文件夹中。

我们的目的是,循环着一个接一个地显示这些图像。 首先布置你的场景树:

../../_images/2d_animation_tree2.webp

备注

根节点也可以是 Area2DRigidBody2D。动画仍然会以同样的方式制作。一旦动画完成,你就可以为 CollisionShape2D 形状分配一个形状。更多信息请参见物理介绍

将精灵表拖拽到 Sprite 的 Texture 属性里,你会看到整个清单显示在屏幕上。要把它分割成单独的帧,请在“检查器”中展开 Animation 部分,将 Hframes 设置为 6HframesVframes 是精灵表中水平和垂直帧的数量。

../../_images/2d_animation_setframes.webp

现在尝试更改 Frame 属性的值。 你会看到它的范围从 05 ,Sprite2D 显示的图像也会相应变化。 这是我们要设置动画的属性。

选中 AnimationPlayer ,然后点击 "动画" 按钮,然后点击 "新建" 按钮. 将新动画命名为 "walk". 将动画长度设置为 0.6 ,点击 "Loop" 按钮,让动画重复播放.

../../_images/2d_animation_new_animation.webp

现在选中 Sprite2D 节点,然后单击钥匙图标,添加一个新轨道。

../../_images/2d_animation_new_track.webp

继续在时间轴的每一点添加帧(默认为 0.1 秒),直到你得到了从 0 到 5 的所有帧。你会看到这些帧出现在动画轨道上:

../../_images/2d_animation_full_animation.webp

按下动画上的“播放”键,看看效果如何。

../../_images/2d_animation_running.gif

控制 AnimationPlayer 动画

与 AnimatedSprite2D 一样,你可以使用 play()stop() 方法通过代码控制动画。 同样,这里是一个在按住右箭头键时播放动画的示例,并在释放该键时停止动画。

extends CharacterBody2D

@onready var _animation_player = $AnimationPlayer

func _process(_delta):
    if Input.is_action_pressed("ui_right"):
        _animation_player.play("walk")
    else:
        _animation_player.stop()

备注

If updating both an animation and a separate property at once (for example, a platformer may update the sprite's h_flip/v_flip properties when a character turns while starting a 'turning' animation), it's important to keep in mind that play() isn't applied instantly. Instead, it's applied the next time the AnimationPlayer is processed. This may end up being on the next frame, causing a 'glitch' frame, where the property change was applied, but the animation was not. If this turns out to be a problem, after calling play(), you can call advance(0) to update the animation immediately.

总结

这些示例说明了可在 Godot 中用于 2D 动画的两个类。AnimationPlayerAnimatedSprite2D 稍微复杂一些,但它提供了额外的功能,因为你还可以为其他属性(如位置或比例)设置动画。 类 AnimationPlayer 也可以与 AnimatedSprite2D 一起使用。 尝试看看什么最适合你的需求。