opolyx 终于有声音了:音效与静音按钮
这款游戏此前完全没有声音。现在骰子、棋子、金钱、拍卖倒计时和胜利提示音都有了声音——并且一个按钮就能全部关闭。

通俗版
在这次更新之前,opolyx 完全不发出任何声音。它不是"安静",而是字面意义上的无声:整个应用里没有任何音频。掷出六点和宣告破产听起来一模一样。
现在,重要的时刻都能听见了。没有循环播放,也没有背景音——每一个声音都对应棋盘上刚刚发生的事:
- 按下"掷骰"的瞬间的骰子声,以及骰子停在点数上时的落定声;
- 你的棋子在棋盘上移动时,每经过一格的脚步声;
- 金钱易手的声音:租金、税款、购买地产、建造;
- 你出价的最后五秒里,拍卖倒计时的滴答声;
- 大奖转盘的声音,以及一局结束时的胜利或失败提示音。
声音默认开启。如果你更喜欢安静地玩,顶栏的喇叭按钮一键即可全部关闭,并且这个选择会记在该设备上——这也是 opolyx 第一次为你保存偏好设置。
我们发布到 YouTube、Instagram 和 TikTok 的精彩片段此前同样是无声的。现在它们采用与游戏相同的音效,所以片段里的破产听起来就和牌桌上的破产一样。
技术细节
播放使用 Web Audio,而不是为每个音效创建一个音频元素。解码后的缓冲区支持复音(骰子落定声与移动脚步声叠加)、样本级精确调度,并且符合现有的内容安全策略——所有文件都由我们自己的域名提供。
哪个事件对应哪个音效,由一个针对引擎事件联合类型的穷尽 switch 决定,因此新增一种领域事件会导致类型检查失败,直到有人决定它是否需要发声:
// lib/sound/events.ts — exhaustive over DomainEvent['kind']
export function soundForEvent(e: DomainEvent, viewerSlot: number | null): SoundId | null {
switch (e.kind) {
case 'rent_paid':
return e.payload.amount >= BIG_RENT ? 'cash-big' : 'cash';
case 'player_bankrupt':
return 'bankrupt';
// …every kind handled; no default, so a new event is a type error
}
}有四个音效由时机驱动而非事件驱动,因为服务器事件到达的时刻并不是玩家感知到动作的时刻。掷骰声在点击时(0 毫秒)响起,落定声在 3D 骰子停稳时响起,脚步声随棋子跳格队列逐格响起,胜负提示音则在结算画面挂载时响起。
| 音效 | 触发时机 |
|---|---|
| dice-roll | 点击时,而非服务器响应时 |
| dice-land | 3D 骰子停稳动画结束时 |
| move-step | 棋子跳格队列中的每一格 |
| tick | 你自己回合或出价的最后 5 秒 |
| victory / defeat | 结算画面挂载时 |
全部 26 个文件均为 CC0 授权,经过裁剪、峰值归一化到 −3 dBFS,并编码为单声道 MP3——选择 MP3 而非 Ogg,是因为 iOS Safari 无法解码 Ogg Vorbis。构建脚本会在编码后校验峰值:早先的版本曾输出时长正确、体积正确却完全听不见声音的文件,原因是一个淡出滤镜把其时间窗之后的一切都变成了静音。
