引言
声音让游戏「有灵魂」——攻击音效、脚步、背景音乐、UI 反馈。Defold 的音频基于 Sound 组件(挂载到 game object 上),通过 msg.post 播放与停止,配合音频分组(group)做音量管理,还支持 3D 音频定位。本文从 Sound 组件与资源格式讲起,逐步覆盖音效触发、音乐循环、音量与淡入淡出、音频分组与混音总线、3D 定位,最后给 Web/移动端的音频工程注意点,让你给 Defold 游戏配一套可管理的音频系统。
前置:/defold-game-engine-introduction/(组件体系)、/defold-script-system-lua/(msg.post 消息)。UI 音效与 GUI 见 /defold-ui-gui/。
目录
- 1. 音频体系总览:Sound 组件与音频分组
- 2. Sound 组件配置与音频资源格式
- 3. 播放音效:play 消息与触发时机
- 4. 背景音乐:循环、切换与淡入淡出
- 5. 音量控制与淡入淡出
- 6. 音频分组(group):主音量、音乐与音效分离
- 7. 3D 音频:声音定位与衰减
- 8. 音频事件:stop 与播放状态管理
- 9. Web/移动端音频注意点
- 10. 速查表
- 延伸阅读
1. 音频体系总览:Sound 组件与音频分组
Defold 音频架构:
Sound 组件(挂在 game object 上)
│
├─ 播放/停止消息(msg.post)
├─ 音频分组(gain/groups)→ 音量总线
└─ 位置属性(3D 定位)
核心概念:
| 概念 | 作用 |
|---|---|
| Sound 组件 | 播放一个音频资源 |
| Audio resource | 音频文件(wav/ogg) |
| group(分组) | 音量总线(主/音乐/音效) |
| gain | 音量增益(0-1) |
| pan | 左右声道平衡 |
心智:Sound 组件是「播放器」,分组是「调音台」——每个音效一个播放器,分组统一管音量。
2. Sound 组件配置与音频资源格式
支持的音频格式:
WAV:无损,用于短音效(界面、打击)
OGG:有损压缩,用于音乐/长音效
FLAC:无损压缩(Web 兼容有限)
推荐:音效用 WAV、音乐用 OGG
Sound 组件属性:
Audio: 选择音频资源
Gain: 音量(0-1,默认 1)
Pan: 左右声道(-1 左 ~ 1 右)
Looping: 是否循环
Pitch: 音高倍率(变调)
Group: 所属音频分组
游戏里引用 Sound 组件:
local sound = msg.url("#sfx_hit") -- 引用组件
msg.post(sound, "play") -- 播放
记忆:短音效用 WAV、音乐用 OGG——Gain 管音量、Looping 管循环、Group 管总线。
3. 播放音效:play 消息与触发时机
播放音效的标准姿势:
-- 攻击命中时触发
function on_hit(self)
msg.post("#sfx_hit", "play")
end
-- 播放时可以设置播放参数(音量/音高变化增加变化感)
msg.post("#sfx_step", "play", { gain = 0.8, pitch = 1.0 })
多音效复用(同一个 Sound 组件播多种变体):
-- 用 pitch 制造随机变调(让连续音效不单调)
local pitch = 0.9 + math.random() * 0.2 -- 0.9 ~ 1.1
msg.post("#sfx_jump", "play", { pitch = pitch })
触发时机要点:
一次性音效:直接 play(如命中、跳跃)
持续音效:play 一次、stop 停止(如引擎声、风声)
注意:频繁触发短音效 → 用独立组件避免抢占
| 场景 | 做法 |
|---|---|
| 一次性(命中/跳跃) | play 即可 |
| 持续(引擎/走路循环) | play + 条件 stop |
| 随机变调 | play 带 pitch 参数 |
| 音量变化 | play 带 gain |
记忆:播放音效就是
msg.post(sound, "play")——加 pitch 变调、gain 控音量,随机 pitch 让音效不呆板。
4. 背景音乐:循环、切换与淡入淡出
背景音乐(BGM)用 Looping 的 Sound 组件:
-- 场景开始播 BGM
msg.post("#bgm", "play")
-- 切换场景/章节 → 换音乐
msg.post("#bgm", "stop")
msg.post("#bgm_alt", "play")
音乐切换的淡入淡出(避免突兀):
-- 淡出当前音乐:逐帧降 gain
local function fade_out(self, sound, duration, on_done)
local start = self.bgm_gain or 1
local t = 0
-- 用 go.animate 或每帧推进
go.animate(sound, "gain", go.PlaybackMode.PLAYBACK_ONCE_FORWARD,
0, go.Easing.IN_QUAD, duration,
function() if on_done then on_done() end end)
end
fade_out(self, "#bgm", 0.8, function()
msg.post("#bgm_alt", "play") -- 淡出后播新歌
end)
音乐管理最佳实践:
1. 全局单例管理 BGM(不随场景销毁)
2. 场景切换先淡出再换
3. 暂停时同时停 BGM
4. 音量尊重用户设置(分组音量)
记忆:BGM 用 Looping + 全局管理——切换用「淡出回调换歌」,暂停时一起停,音量归分组管。
5. 音量控制与淡入淡出
音量是 Sound 组件的 gain 属性——可以动态动画:
-- 直接设音量
go.set("#sfx_hit", "gain", 0.5)
-- 用 go.animate 做淡入淡出(见 go.animate 用法)
go.animate("#sfx_hit", "gain", go.PlaybackMode.PLAYBACK_ONCE_FORWARD,
0.8, go.Easing.IN_QUAD, 0.5) -- 淡入到 0.8
-- 淡出(音效结束用)
go.animate("#sfx_hit", "gain", go.PlaybackMode.PLAYBACK_ONCE_FORWARD,
0, go.Easing.OUT_QUAD, 0.3)
淡入淡出的应用:
| 场景 | 做法 |
|---|---|
| 进入界面播音乐 | gain 0 → 1 淡入 |
| 音效结束 | gain → 0 淡出 + stop |
| 暂停游戏 | 全局音效淡出 |
| 恢复 | 淡回原音量 |
记忆:gain 就是音量旋钮——go.animate 它就能淡入淡出,暂停游戏时全局淡出最有质感。
6. 音频分组(group):主音量、音乐与音效分离
分组让「音乐和音效各自调音量」——玩家最爱的开关就在这:
-- 设置整个分组的音量(0-1)
msg.post("@system:", "set_gain", { group = "music", gain = 0.6 })
msg.post("@system:", "set_gain", { group = "sfx", gain = 0.8 })
-- 读取分组音量
local g = msg.post("@system:", "get_gain", { group = "music" })
分组设计:
master(总音量)→ 调全局
music(音乐)
sfx(音效)
ui(界面音)
voice(语音)
游戏里落地:
-- 设置界面:把玩家的音量偏好写进分组
local function apply_volume(self)
msg.post("@system:", "set_gain", { group = "music", gain = self.vol_music })
msg.post("@system:", "set_gain", { group = "sfx", gain = self.vol_sfx })
end
记忆:分组 = 独立音量总线——
@system:的 set_gain 调整个组,玩家音量设置存下来再 apply。
7. 3D 音频:声音定位与衰减
3D 音频 = 声音跟随物体位置,近大远小:
-- 监听器(耳朵):通常挂到玩家
local listener = msg.url("#player_audio_listener")
-- 让声音根据游戏物体位置定位:
-- Sound 组件挂到发声物体上,位置决定声像
-- 设置监听器增益(近距音量)
msg.post(listener, "set_listener", { gain = 1 })
3D 音频的衰减参数:
Falloff:声音随距离衰减曲线
Rolloff:衰减速率
Range:可听距离
Pan:位置在监听器左右 → 自动声像
配置 3D 音频:
1. 每个发声物体挂 Sound 组件(位置即声源)
2. 玩家/相机挂 Listener 组件
3. 调 Falloff/Rolloff 控制衰减手感
记忆:3D 音频 = 声源组件 + 监听器组件 + 衰减曲线——声源挂物体、监听挂玩家,近大远小自动出来。
8. 音频事件:stop 与播放状态管理
播放状态管理(避免音效叠爆/残留):
-- 停止播放
msg.post("#sfx_engine", "stop")
-- 判断是否在播放(用 go.get)
local playing = go.get("#sfx_engine", "playing") -- true/false
if not playing then
msg.post("#sfx_engine", "play")
end
音效抢占策略:
同一个 Sound 组件再次 play → 打断重播
不同组件 → 同时播放(重叠)
需要「每次点击都响」→ 多个组件轮换(round-robin)
轮换组件防叠音:
-- 3 个脚步音效组件轮换
self.step_idx = (self.step_idx or 0) % 3 + 1
msg.post("#sfx_step" .. self.step_idx, "play")
记忆:stop 停播放、playing 查状态——高频音效用「多组件轮换」防叠音,这是脚步声的标准做法。
9. Web/移动端音频注意点
Web 端(HTML5)音频的特殊性:
1. 浏览器自动播放限制:无用户交互前不能播音频
→ 首次点击后解锁(play 一次空音)
2. 格式兼容:优先 OGG/MP3,旧浏览器要 wav
3. 音频加载:懒加载,避免首屏大 OGG
移动端注意点:
1. 后台/切前台:监听系统事件暂停/恢复音频
2. 静音开关:尊重手机静音键(系统静音则游戏音不响)
3. 体积:音乐用 OGG 压体积,音效控制数量
4. 内存:卸载不用的大音频资源
Web 解锁代码:
-- 首次点击解锁音频
local function unlock_audio(self)
msg.post("#bgm", "play") -- 触发一次播放解锁
self.unlocked = true
end
function on_input(self, action_id, action)
if not self.unlocked and action.pressed then
unlock_audio(self)
end
end
记忆:Web 要「首次交互解锁音频」、移动端要「尊重系统静音」——平台差异别忽略,否则真机上没声。
10. 速查表
| 需求 | 做法 |
|---|---|
| 播放音效 | msg.post("#sfx", "play") |
| 停止音效 | msg.post("#sfx", "stop") |
| 随机变调 | play 带 pitch 参数 |
| 音量 | go.set("#sfx", "gain", 0.5) |
| 淡入淡出 | go.animate("#sfx", "gain", ...) |
| 循环 BGM | Sound 组件 Looping + play |
| 音乐切换 | 淡出回调 → 播新组件 |
| 分组音量 | @system: set_gain {group, gain} |
| 3D 音频 | 声源 + Listener + Falloff |
| 防叠音 | 多组件轮换 |
| Web 解锁 | 首次交互后 play |
| 移动静音 | 尊重系统静音键 |
一句话记忆:Defold 音频 = Sound 组件播放 + group 分组调音 + gain 控音量;音效 play 带 pitch 随机、BGM 用 Looping 全局管、淡入淡出用 go.animate;3D 定位靠声源+Listener+衰减;高频音效多组件轮换、Web 首次交互解锁、移动端尊重静音——一套音频系统吃透游戏声效。
延伸阅读
- /defold-script-system-lua/ — msg.post 消息驱动
- /defold-game-engine-introduction/ — 组件体系
- /defold-ui-gui/ — UI 音效与界面
- /defold-game-engine-complex-logic-state-management/ — 状态机与音频联动
- /defold-performance-optimization/ — 音频资源优化
- [[graphics]] — 多媒体渲染与音频编码
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。