title: Defold 中的逐帧动画
逐帧动画就是由一些列静态图片轮流显示生成的动画. 这种技术类似于老式翻页动画 (详见 http://en.wikipedia.org/wiki/Traditional_animation). 由于每帧的独立性使得这种技术很自由. 但是每帧一张图片会很耗费内存. 相似图片越多动画过渡越平滑同时也带来了巨大的工作量. Defold 逐帧动画使用来自于 图集, 或者 瓷砖图源 里水平排列的图片.
Sprite 和 GUI 方块节点可以用来播放逐帧动画而且可以在运行时进行控制.
Sprites
: 通过调用 sprite.play_flipbook() 函数播放逐帧动画. 示例见下文.
GUI 方块节点
: 通过调用 gui.play_flipbook() 函数播放逐帧动画. 示例见下文.
::: sidenote ping-pong 播放模式把动画从第一帧播放到最后一帧再反向播放到 第二帧 , 而不是第一帧. 这样便于连续播放的衔接. :::
假设你的游戏有个 "dodge" 功能, 按下指定的键主角就进行闪避动作. 为此你建立了四组动画:
"idle" : 主角待机的循环动画.
"dodge_idle" : 主角闪避动作的循环动画.
"start_dodge" : 主角从站立姿态到闪避动作的一次性动画.
"stop_dodge" : 主角从闪避动作到站立姿态的一次性动画.
逻辑代码如下:
local function play_idle_animation(self)
if self.dodge then
sprite.play_flipbook("#sprite", hash("dodge_idle"))
else
sprite.play_flipbook("#sprite", hash("idle"))
end
end
function on_input(self, action_id, action)
-- "dodge" 就是输入动作
if action_id == hash("dodge") then
if action.pressed then
sprite.play_flipbook("#sprite", hash("start_dodge"), play_idle_animation)
-- 记录闪避动作已开始
self.dodge = true
elseif action.released then
sprite.play_flipbook("#sprite", hash("stop_dodge"), play_idle_animation)
-- 记录闪避动作完成
self.dodge = false
end
end
end
给节点选择图片或者动画时, 实际上也同时指定了图片来源 (图集或者瓷砖图源) 以及默认动画. 节点图源是静态的, 但是当前播放的动画是可以在运行时指定的. 静态图片被视作单帧动画, 所以运行时切换图片相当于播放另一个动画:
function init(self)
local character_node = gui.get_node("character")
-- 新动画/图片播放时
-- 节点图源要存在默认动画.
gui.play_flipbook(character_node, "jump_left", flipbook_done)
end
动画函数 (sprite.play_flipbook() 和 gui.play_flipbook()) 可以在最后一个参数上传入Lua回调函数. 当动画播放完成时会调用这个函数. 对于循环动画和用 go.cancel_animations() 手动取消播放的动画, 不会调用回调函数. 动画播放完成的回调函数里可以发送消息或者继续播放其他动画. 例如:
local function flipbook_done(self)
msg.post("#", "jump_completed")
end
function init(self)
sprite.play_flipbook("#character", "jump_left", flipbook_done)
end
local function flipbook_done(self)
msg.post("#", "jump_completed")
end
function init(self)
gui.play_flipbook(gui.get_node("character"), "jump_left", flipbook_done)
end