一、前言
本篇是上一节文章:Godot3游戏引擎入门之四:给主角添加动画(上)的继续。在这两篇文章里,我会详细讲述 Godot 3 中制作简单精灵动画的三种方法,其中上部分包含两种,下部分讨论第三种方式。 :smile:
主要内容: Godot 2D 小游戏入门之三种动画创建方式(第三种)
阅读时间: 8-10 分钟
永久链接:http://liuqingwen.me/blog/2018/09/27/introduction-of-godot-3-part-4-add-some-cute-animations-part-2/
系列主页:http://liuqingwen.me/blog/tags/Godot/
二、正文
本篇目标
- 使用动画精灵 AnimatedSprite 节点创建 Sprite 骑士动画(上篇)
- 使用 Sprite 节点和 GDScript 脚本代码共同创建背景滚动效果(上篇)
- 使用 AnimationPlayer 节点制作天鹅飞舞的关键帧动画(下篇)
创建动画
首先,简单回顾一下本篇上节内容中的两种游戏动画制作方式:
第一种方法:使用 AnimatedSprite 制作骑士动画
非常简单又符合直觉的一种方法,最适合于打造单个人物或物件的精灵动画特效。 AnimatedSprite 制作动画的原理相当简单,只需要提前准备好必须的图片资源即可,具体操作参考上节的内容。
第二种方法:使用代码控制背景天空滚动
这种方式相对第一种可以说是最符合程序员的思维习惯的的:通过代码直接控制并移动背景图片的位置就能达到我们所想要的动画特效。在上一节内容中,我们还了解到了 Godot 中图片的坐标原点位置的相关设置。
第三种方法:使用 AnimationPlayer 关键帧制作天鹅动画
上文介绍的两种动画制作方式简单也不失灵活性,在实际游戏开发过程中使用的也会比较多,但是,如果你认为 Godot 就这点能耐的话,那你也太小看它了,哈哈。接下来我们开始探讨第三种动画制作方式:关键帧动画!现在,隆重请出我们今天的主角: AnimationPlayer ! :sunglasses:
在深入讨论之前,我们先了解一下 SpriteSheet 相关知识,如果你有使用过 LibGDX 跨平台游戏框架开发游戏的经验,或者熟悉 Unity 中的 2D 游戏动画制作,那么你肯定对 SpriteSheet 会非常了解。我们想象一下第一种动画方式,使用 AnimatedSprite 制作动画虽然简单,但是如果涉及到人物多种状态,比如攻击、跳跃、行走、死亡等,那么图片资源是不是会多如牛毛?而且操作过程中还容易出错,这就是 SpriteSheet 的由来之处了!简而言之, SpriteSheet 就是把很多图片,甚至不同类型的图片资源,放到一个大图片里,方便管理操作和使用,听说过 TexturePacker 这个软件吗?它就是专门干这事的。
理论到此结束,我们来瞻仰一下我们要实现的天鹅动画的图片资源 SpriteSheet 精灵图集:
图片结构很单一,可以看得出是由 8 张连续的小图拼接而成的,怎么使用呢?首先,我们还是和往常一样使用一个 Sprite 精灵节点来显示天鹅图片,改名为 Swan ,但是这里还需要进行一些简单的设置:
如上图,我们设置属性 Vframes 值为 1 , Hframes 为 8 ,意思很明确,即纵向分 1 帧,横向分 8 帧,然后总共 1x8 帧,而第三个属性 Frame 就表示当前显示第几帧画面,可以设置为 0-7 共 8 帧画面,操作浏览一下效果试试,你会发现 Frame 值从 0 到 1 然后慢慢设置到 7 的时候,天鹅图片就产生了一种不连续的动画效果,对,动画原理就是这么简单!这个时候你会想:我如果在代码中获取 Swan 的 Frame 属性,然后把它的值每次往前加 1 不就可以生成动画了吗?的确可以!代码如下:
func _process(delta):
if $Swan.frame == 7:
$Swan.frame = 0
else:
$Swan.frame += 1
这和第二种方法的道理完全相同,也很值得一试!不过运行游戏场景后,你会发现天鹅飞舞的动画太快了!当然,这并不是什么大问题,添加一个时间控制的变量,让帧属性慢点往前加 1 就可以了。不过这不是我们要讨论的重点,我所要给大家介绍的是 Godot 中强大到能够控制一切的关键帧动画节点工具: AnimationPlayer !
对,在 Godot 中 AnimationPlayer 的确能操纵一切,简单的如位置、旋转、缩放的控制,还有其他节点的任意属性值的控制,甚至连方法的调用都能在 AnimationPlayer 中进行动画设定!同时,不仅强大,使用起来也非常简单。如何实现天鹅动画,这里我做了一个简单的操作示意图,大家可以感受下 AnimationPlayer 节点的使用步骤:
下面进入细节部分,首选我们需要在游戏根节点下创建一个 AnimationPlayer 节点,这里要强调一下:我们要对 Swan 节点进行动画,所以他们需要放置在同一级别上!当然, AnimationPlayer 完全可以同时对其他节点比如天空背景或者主角骑士节点进行动画,你可以尝试一下。接下来,选择 AnimationPlayer 节点,新建一个动画轨道:
然后对我们新建的动画轨道进行设置:自动播放、重复播放、动画时长等,部分细节如下图:
OK ,大功告成,运行结果:
最后,虽然动画有了但是天鹅并不能移动位置,我们需要让它随着时间不断移动位置就可以了。这里介绍一个小技巧:我们可以直接在节点上添加脚本! Godot 推荐我们这么做,尽量让每一个节点独立,也就是和整个游戏场景解耦,在大项目中让合作开发更高效。
Talk is cheap, show me the code! 选择 Swan 节点,点击添加脚本,编写代码:
extends Sprite
# 速度常量
const SPEED = 100
# 最左边界和最右边界
var minX = -100
var maxX = 800
func _process(delta):
position.x -= SPEED * delta
# 如果天鹅飞到左边边界,把它的x坐标置为最右边界
if position.x < minX:
position.x = maxX
最终效果:
所有代码
我们的游戏终于完成了,这里我附上所有的代码,如果你已经阅读过前面两篇文章:Godot3游戏引擎入门之三:移动我们的主角,那么请跳过。
# 继承于Node2D
extends Node2D
# 常量,表示速度(像素)
const SPEED = 200
const SKY_SPEED = 50
# 定义一些变量,不需要类型
var maxX = 600 # 角色运动右边界
var minX = 0 # 角色运动左边界
# onready关键词使变量在场景加载完后赋值,保证不为null
onready var knight = self.get_node("Knight")
# 在Godot中$符号可以直接加子节点名字获得子节点对象,相当于get_node方法
onready var sky1 = $Sky1
onready var sky2 = $Sky2
# 节点进入场景开始时调用此方法,常用作初始化
func _ready():
maxX -= knight.frames.get_frame('idle', 0).get_size().x / 2
minX += knight.frames.get_frame('idle', 0).get_size().x / 2
# 每一帧运行此方法,delta表示每帧间隔
func _process(delta):
# 移动背景天空位置,生成滚动动画
updateSkyAnimation(SKY_SPEED * delta)
# Input表示设备输入,这里D和右光标表示往右动
if Input.is_key_pressed(KEY_D) or Input.is_key_pressed(KEY_RIGHT):
moveKnightX(1, SPEED, delta)
return
elif Input.is_key_pressed(KEY_A) or Input.is_key_pressed(KEY_LEFT):
moveKnightX(-1, SPEED, delta)
return
# 没有键盘控制,让骑士动画为idle状态
if knight.animation != 'idle':
knight.animation = 'idle'
func updateSkyAnimation(speed):
# 移动,更新背景的位置
sky1.position.x -= speed
sky2.position.x -= speed
# 如果滚动到最左边,那么移动到右边来
if sky1.position.x <= -1200:
sky1.position.x += 2400
elif sky2.position.x <= -1200:
sky2.position.x += 2400
# 自定义函数,direciton表示方向,speed表示速度,delta是帧间隔
func moveKnightX(direction, speed, delta):
# 有键盘控制,让骑士动画为run状态,跑起来
if knight.animation != 'run':
knight.animation = 'run'
if direction == 0:
return
# position属性为节点当前置,Vector2向量简单乘法
knight.position += Vector2(speed, 0) * delta * direction
# 越界检测
if knight.position.x > maxX:
knight.position = Vector2(maxX, knight.position.y)
elif knight.position.x < minX:
knight.position = Vector2(minX, knight.position.y)
knight.scale = Vector2(direction, 1)
三、小结(下)
三种方式已经全部讲解完毕,这里简单总结一下 Godot 3 中动画制作三种方式的优缺点:
节点名 | AnimatedSprite | Sprite + GDScript | AnimationPlayer |
---|---|---|---|
优点 | 简单明了,最适合制作主角多种状态动画 | 思路清晰,适合简单的动画,代码可控度高 | 最强大的动画系统,几乎能操纵一切元素来实现复杂的动画 |
缺点 | 只能使用图片,而且必须使用很多张图片,资源文件数量大增 | 对于复杂的属性动画很难使用代码达到理想效果 | 仅仅操作稍复杂点,节点的位置必须同级别 |
本篇上下节内容结束,还是那句话:原创不易啊,希望大家喜欢! :smile:
我的博客地址: http://liuqingwen.me ,欢迎关注我的微信公众号: