Defold 精灵与动画:Sprite、Flipbook、缓动与程序动画

系统覆盖 Defold 精灵动画:Sprite 组件与图集、Flipbook 逐帧动画、go.animate 缓动系统、帧动画切换、程序化动画(曲线控制)、Spine/DragonBones 骨骼动画集成、动画状态机。

引言

动画是游戏「活」起来的关键。Defold 的动画体系分为三层:Sprite(静态精灵)→ Flipbook(逐帧动画)→ 程序动画(go.animate 缓动),再叠加骨骼动画(Spine)与动画状态机。本文从最基础的 Sprite 组件讲起,逐步覆盖图集与 Flipbook 帧动画、go.animate 的属性缓动系统(位置/旋转/缩放)、动画播放控制与回调、程序化动画曲线,最后讲 Spine/DragonBones 骨骼动画集成与实战动画状态机,让你给 Defold 角色配上流畅的动作系统。

前置:/defold-game-engine-introduction/(组件体系)、/defold-script-system-lua/(msg 与生命周期)。物理表现见 /defold-physics-collision/。


目录


1. 动画体系总览:三层动画模型

Defold 动画的三种形态:

① Sprite(静态):一张图 → 换图切帧
② Flipbook(逐帧):图集多帧循环 → 传统动画
③ 程序动画(go.animate):属性插值 → 移动/旋转/缩放/透明度
   └─ 骨骼动画(Spine/DragonBones):复杂角色骨骼驱动

各自适用场景:

方式适用性能制作
Sprite 换图简单状态(换表情)极高美术出图
Flipbook跑动/攻击逐帧高帧序列
go.animate位移/UI/粒子运动极高代码控制
Spine角色骨骼动画中骨骼软件

心智:动画 = 让「属性或帧」随时间变化——先想清楚要动什么,再选这三层里的对应工具。


2. Sprite 组件与图集(Atlas)

Sprite 组件显示一张图——图集(Atlas)统一管理图片资源:

Atlas(图集):
  把多张图片打包成一张大图 + 元数据
  好处:一次纹理上传、精灵按名引用

代码里创建 Sprite 并换图:

-- 给 game object 添加 sprite 组件
local sp = msg.url("#sprite")      -- 引用 sprite 组件

-- 播放图集中的某张图(Flipbook 或静态帧)
sprite.play_flipbook(sp, hash("idle"))
-- 或直接换静态图
msg.post(sp, "set_texture", { texture = resource.get_atlas("atlas:main") })

Sprite 常用属性(go.get/set):

go.set(sp, "scale", vmath.vector3(2, 2, 2))    -- 缩放
go.set(sp, "tint", vmath.vector4(1, 0.5, 0.5, 1)) -- 染色(命中闪白)
go.set(sp, "size", vmath.vector3(128, 128, 0))   -- 渲染尺寸
属性作用常用场景
scale缩放放大缩小
tint染色受击闪白/阵营颜色
size尺寸自适应
flip翻转(水平/垂直)朝向切换

记忆:Sprite = 图集里的一张图 + 渲染属性——换图用 sprite.play_flipbook、调属性用 go.set。


3. Flipbook 逐帧动画:定义与播放

Flipbook = 图集里的一组帧,按序列播放:

制作流程:
1. 美术导出帧序列:walk_1.png … walk_8.png
2. 导入 Defold → 图集自动生成 Flipbook 动画:walk
3. 代码播放动画名字

播放 Flipbook:

local sp = msg.url("#sprite")

-- 播放一次(p 参数)
sprite.play_flipbook(sp, hash("walk"), { playback = go.PlaybackMode.PLAYBACK_ONCE_FORWARD })
-- 循环播放
sprite.play_flipbook(sp, hash("walk"), { playback = go.PlaybackMode.PLAYBACK_LOOP_FORWARD })
-- 倒放/镜像
sprite.play_flipbook(sp, hash("walk"), { playback = go.PlaybackMode.PLAYBACK_ONCE_BACKWARD })

播放模式速查:

PlaybackMode行为
ONCE_FORWARD正向播一次
ONCE_BACKWARD反向播一次
LOOP_FORWARD正向循环
LOOP_BACKWARD反向循环
LOOP_PINGPONG来回循环

手动控制帧(帧精度控制):

-- 手动设置当前帧(按索引)
sprite.set_hflip(sp, true)     -- 水平翻转
-- 或设置动画进度
go.set(sp, "cursor", 0.5)      -- 播到 50%

记忆:Flipbook 是「帧序列 + 播放模式」——playback 参数决定播一次/循环/来回,适合跑动攻击等帧动画。


4. go.animate 缓动系统:位置/旋转/缩放动画

go.animate = 让任意属性随时间插值变化——Defold 程序动画的核心:

-- 移动:让 position 从当前位置动画到目标
go.animate(".", "position", go.PlaybackMode.PLAYBACK_ONCE_FORWARD,
           vmath.vector3(100, 100, 0), go.Easing.LINEAR, 2.0)

-- 旋转
go.animate(".", "rotation", go.PlaybackMode.PLAYBACK_ONCE_FORWARD,
           vmath.quat_rotation_z(math.rad(180)), go.Easing.IN_OUT_QUAD, 1.0)

-- 缩放
go.animate(".", "scale", go.PlaybackMode.PLAYBACK_LOOP_PINGPONG,
           vmath.vector3(1.5, 1.5, 1), go.Easing.OUT_BOUNCE, 0.5)

-- 透明(GUI/Sprite 染色 alpha)
go.animate("#sprite", "tint.w", go.PlaybackMode.PLAYBACK_ONCE_FORWARD,
           0, go.Easing.IN_QUAD, 0.3)

go.animate 签名:

go.animate(url, property, playback, to, easing, duration)
--       对象    属性      模式      目标值  曲线    时长(秒)
参数说明
property属性(position/rotation/scale/tint.w…)
playback播放模式(同 Flipbook)
to目标值
easing缓动曲线(见下节)
duration时长(秒)

记忆:go.animate 五要素——属性、模式、目标值、曲线、时长——位置/旋转/缩放/透明度都能动,UI 与角色运动一网打尽。


5. 缓动曲线与 Easing 类型

缓动曲线决定「快慢节奏」——从线性到弹性:

LINEAR        匀速
IN_QUAD       先慢后快
OUT_QUAD      先快后慢
IN_OUT_QUAD   两头慢中间快
OUT_BOUNCE    结束弹跳
OUT_ELASTIC   结束回弹
IN_BACK / OUT_BACK   超出再回(回拉效果)

曲线选型直觉:

场景推荐 Easing
匀速移动(滚屏)LINEAR
加速下落(重力)IN_QUAD
减速到位(UI 滑入)OUT_QUAD
弹跳(落地面)OUT_BOUNCE
回弹(弹性按钮)OUT_ELASTIC
-- 按钮回弹效果
go.animate("#btn", "scale", go.PlaybackMode.PLAYBACK_LOOP_PINGPONG,
           vmath.vector3(1.1, 1.1, 1), go.Easing.OUT_ELASTIC, 0.8)

记忆:缓动曲线是「动感的灵魂」——匀速平铺、回弹有趣、弹性 Q 弹,游戏手感全靠它调。


6. 动画控制:播放、停止、暂停与回调

控制正在进行的动画:

-- 取消所有正在进行的 go.animate 动画
go.cancel_animations(".", "position")
-- 取消该对象所有属性动画
go.cancel_animations(".", go.PROP_ANIM_POSITION)

-- 停止 Flipbook 播放
msg.post("#sprite", "play_animation", { id = hash("idle"), playback = ... })

动画完成回调(animation_done 消息):

-- 在 receive_message 里监听
function on_message(self, message_id, message, sender)
    if message_id == hash("animation_done") then
        -- message.animation_id 是刚播完的动画名
        -- 用于:播完攻击→回待机;播完死亡→销毁
        print("动画播完:", message.animation_id)
    end
end

播放完成后的链式动画:

-- 攻击动画播完 → 自动回待机
function on_message(self, message_id, message, sender)
    if message_id == hash("animation_done") then
        sprite.play_flipbook("#sprite", hash("idle"), { playback = go.PlaybackMode.PLAYBACK_LOOP_FORWARD })
    end
end

记忆:动画编排靠 animation_done 回调——播完攻击接待机、播完死亡接销毁,一条链把动作串起来。


7. 程序化动画:曲线路径与贝塞尔控制

go.animate 只能直线/单属性——复杂路径要程序控制:

正弦浮动(敌人上下漂浮):

-- 每帧更新 y 位置
local t = self.t or 0
self.t = t + dt * 2.0

local base_y = self.base_y or 0
go.set(".", "position.y", base_y + math.sin(self.t) * 20)

贝塞尔曲线路径(弹道/引导子弹):

-- 二次贝塞尔:P(t) = (1-t)²P0 + 2(1-t)t·P1 + t²·P2
local function quad_bezier(p0, p1, p2, t)
    local it = 1 - t
    return it * it * p0 + 2 * it * t * p1 + t * t * p2
end

-- 每帧推进 t
self.t = math.min(self.t + dt * self.speed, 1)
local x = quad_bezier(self.start.x, self.ctrl.x, self.end.x, self.t)
local y = quad_bezier(self.start.y, self.ctrl.y, self.end.y, self.t)
go.set(".", "position", vmath.vector3(x, y, 0))

插值工具:

手段用途
每帧计算 + go.set任意曲线
math.sin周期性浮动
贝塞尔平滑路径
vmath.lerp两值线性插值

记忆:复杂运动 = 每帧「算好位置再 set」——go.animate 管简单插值,正弦/贝塞尔管花活。


8. Spine/DragonBones 骨骼动画集成

骨骼动画 = 用「骨骼」驱动蒙皮,适合复杂角色(四肢、表情):

Spine / DragonBones:
  美术在骨骼软件里摆动作
  导出 JSON + 纹理图集
  Defold 加载 → 作为骨骼动画资源播放

集成步骤:

1. 导出 Spine JSON + atlas
2. 拖入 Defold 资源 → 自动生成模型组件
3. 代码控制骨骼动画

代码控制骨骼动画:

-- 播放骨骼动画(通过模型组件)
local model = msg.url("#model")
msg.post(model, "play_anim", { id = hash("run") })

-- 监听播完
function on_message(self, message_id, message, sender)
    if message_id == hash("animation_done") then
        msg.post("#model", "play_anim", { id = hash("idle") })
    end
end

骨骼 vs Flipbook 选择:

维度Flipbook骨骼动画
灵活性固定帧骨骼实时变换
体积每帧一张图一套骨骼 + 蒙皮
制作成本逐帧画骨骼绑定
适合像素/低面复杂角色

记忆:角色复杂用 Spine/DragonBones,简单用 Flipbook——骨骼动画一套动作多方向复用,代价是绑定成本。


9. 动画状态机:从待机到攻击的实战

角色动画状态机(有限状态机,参考 /defold-game-engine-complex-logic-state-management/):

-- 状态定义
local STATE = { IDLE = 1, RUN = 2, ATTACK = 3, HURT = 4, DEAD = 5 }

-- 状态 → 动画映射
local ANIM = {
    [STATE.IDLE]   = hash("idle"),
    [STATE.RUN]    = hash("run"),
    [STATE.ATTACK] = hash("attack"),
    [STATE.HURT]   = hash("hurt"),
    [STATE.DEAD]   = hash("dead"),
}

function init(self)
    self.state = STATE.IDLE
end

-- 切状态统一入口
local function set_state(self, new_state)
    self.state = new_state
    local anim = ANIM[new_state]
    local playback = go.PlaybackMode.PLAYBACK_ONCE_FORWARD
    if new_state == STATE.IDLE or new_state == STATE.RUN then
        playback = go.PlaybackMode.PLAYBACK_LOOP_FORWARD   -- 待机/跑动循环
    end
    sprite.play_flipbook("#sprite", anim, { playback = playback })
end

-- 攻击播完 → 回待机
function on_message(self, message_id, message, sender)
    if message_id == hash("animation_done") then
        if self.state == STATE.ATTACK then set_state(self, STATE.IDLE) end
    end
end

记忆:动画状态机 = 状态 → 动画映射 + 统一切换函数 + animation_done 回稳态——一套映射管住所有动作,避免动画乱飞。


10. 速查表

需求做法
显示一张图Sprite + Atlas
播逐帧动画sprite.play_flipbook(sp, hash("walk"), ...)
属性动画go.animate(".", "position", ..., target, easing, dur)
循环播放playback = LOOP_FORWARD
弹性/弹跳go.Easing.OUT_ELASTIC / OUT_BOUNCE
取消动画go.cancel_animations(".", "position")
播完回调监听 animation_done
浮动/路径每帧 sin/贝塞尔 + go.set
骨骼动画Spine/DragonBones 导出 + model.play_anim
状态机STATE→ANIM 映射 + set_state + 回调回稳态

一句话记忆:动画三层——Sprite 换图、Flipbook 帧序列、go.animate 属性插值;播放模式管循环、Easing 管手感、animation_done 管串联;复杂角色上 Spine、花活路径走每帧贝塞尔、状态机用映射统一——Defold 动画体系一条链路全打通。


延伸阅读

  • /defold-game-engine-complex-logic-state-management/ — 状态机与 AI 行为
  • /defold-script-system-lua/ — msg 消息与生命周期
  • /defold-editor-asset-pipeline/ — 图集与资源管线
  • /defold-ui-gui/ — GUI 动画与 HUD
  • /defold-performance-optimization/ — 精灵性能优化
  • [[graphics]] — 2D 渲染与图集原理

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「defold」更多文章

  1. Defold 音频系统:Sound 组件、背景音乐、3D 音效与声音管理
  2. Defold 着色器与后处理:GLSL 材质、特效与全屏后期
  3. Defold 性能优化:Draw Call、图集合并、内存与 Profiler 实战