Skip to content

声音与按键

背景:脚步声和环境音效共用一个全局音量;Ctrl+Space 在三个模块中被同时注册,静默覆盖。 过程:AudioBus 类 → 音量分组;ShortcutRegistry 类 → 注册冲突检测。


联邦能走了,也能跳了。但有些声音在打架。

脚步声和环境音效共用一个全局音量变量。调大,脚步声和音乐一起大。调小,三个一起小。

用户在 GitHub 上提了一个 issue。问题不在翻译,在体验。

Wails 的事件系统是后注册覆盖先注册。Ctrl+Spacemain.ts 里注册——切换动作模式。在 scene.ts 里也注册——切换相机模式。在 outfit.ts 里也注册——切换服装预设。

最后一个注册的覆盖前两个。用户不知道。

"这不对,"桌面壳说。

它打开 audio.ts,找到那个叫 volume 的数字。它打开 main.tsscene.tsoutfit.ts,找到三个 document.addEventListener('keydown')

"三个模块,同一个键。" 外交官说。

"而且没人知道。"


一、三个通道

桌面壳在 src/core/audio-bus.ts 里新建了一个类:AudioBus

一个 Map,把 channel 按名字存起来。每个 channel 属于一个组:sfxambientmusic

每个 AudioChannel 内部是一个 GainNode——Web Audio API 的音量节点。所有音效通过它输出到扬声器。

组之间互不干扰。调 sfx 组的音量,ambientmusic 不受影响。

三个组之上还有一个 master gain。所有组的输出先汇聚到 master,再输出。

脚步声归 sfx,风声归 ambient,音乐归 music


二、一个登记簿

src/core/shortcut-registry.tsShortcutRegistry 类。

注册时检查冲突:

typescript
register(key, handler, source) {
    if (this.shortcuts.has(key)) {
        const existing = this.shortcuts.get(key)!;
        console.warn(`快捷键冲突: ${key} 被 ${existing.source} 和 ${source} 注册`);
    }
    this.shortcuts.set(key, { handler, source });
}

先注册的生效,后注册的被忽略。但控制台会打印一条警告,告诉开发者有冲突。

注销需要同时匹配 key 和 source——防止误删其他模块注册的同一个键。


三、修复

Ctrl+Space 的冲突被发现后,scene.tsoutfit.ts 的快捷键改为其他 key。main.ts 保留了 Ctrl+Space——动作模式是最常用的快捷键。

桌面壳在设置页加了混音器界面。四个滑块:主音量、音效、环境、音乐。用户在设置页调整脚步声的音量,不需要重启应用,不需要改代码。


尾声

声音有了各自的去处。

键盘有了字典。

联邦不再只有一个音量,也不再只有一个键。


教训:分散式的快捷键注册是协作型 bug 的源头——单独看每个模块,都是正确的。冲突只存在于"放在一起"的时候。