Appearance
声音与按键
背景:脚步声和环境音效共用一个全局音量;Ctrl+Space 在三个模块中被同时注册,静默覆盖。 过程:AudioBus 类 → 音量分组;ShortcutRegistry 类 → 注册冲突检测。
联邦能走了,也能跳了。但有些声音在打架。
脚步声和环境音效共用一个全局音量变量。调大,脚步声和音乐一起大。调小,三个一起小。
用户在 GitHub 上提了一个 issue。问题不在翻译,在体验。
Wails 的事件系统是后注册覆盖先注册。Ctrl+Space 在 main.ts 里注册——切换动作模式。在 scene.ts 里也注册——切换相机模式。在 outfit.ts 里也注册——切换服装预设。
最后一个注册的覆盖前两个。用户不知道。
"这不对,"桌面壳说。
它打开 audio.ts,找到那个叫 volume 的数字。它打开 main.ts、scene.ts、outfit.ts,找到三个 document.addEventListener('keydown')。
"三个模块,同一个键。" 外交官说。
"而且没人知道。"
一、三个通道
桌面壳在 src/core/audio-bus.ts 里新建了一个类:AudioBus。
一个 Map,把 channel 按名字存起来。每个 channel 属于一个组:sfx、ambient、music。
每个 AudioChannel 内部是一个 GainNode——Web Audio API 的音量节点。所有音效通过它输出到扬声器。
组之间互不干扰。调 sfx 组的音量,ambient 和 music 不受影响。
三个组之上还有一个 master gain。所有组的输出先汇聚到 master,再输出。
脚步声归 sfx,风声归 ambient,音乐归 music。
二、一个登记簿
src/core/shortcut-registry.ts。ShortcutRegistry 类。
注册时检查冲突:
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.ts 和 outfit.ts 的快捷键改为其他 key。main.ts 保留了 Ctrl+Space——动作模式是最常用的快捷键。
桌面壳在设置页加了混音器界面。四个滑块:主音量、音效、环境、音乐。用户在设置页调整脚步声的音量,不需要重启应用,不需要改代码。
尾声
声音有了各自的去处。
键盘有了字典。
联邦不再只有一个音量,也不再只有一个键。
教训:分散式的快捷键注册是协作型 bug 的源头——单独看每个模块,都是正确的。冲突只存在于"放在一起"的时候。