Files
xsl 0652c2f0e6 research(hunt-sim): 10 人并发在线模拟×多 agent 设计迭代——研究设施与全套档案
研究命题(00-plan):验证并打磨《围猎》联机纯音频体验——不是逻辑能跑通,
而是真人玩起来是什么体验、愿不愿意再来一局。

设施 web/harness/hunt-sim/(可复用,零依赖):
- arena.mjs 编排器:起真实服务器(随机端口+临时数据目录隔离),10 个拟人客户端
  经真实 WS 同时在线,错峰组队、真实时长对局、局间状态跨轮维护
- sim-client.mjs:game.js 行为移植(协议+手势路由+R1-R8 音频调度逐字节对齐),
  产出「玩家耳朵听到什么」的感知时间线(语音全文/loop 方位音量档/喊话/震动)
- brain.mjs:人设大脑——察觉延迟/前后判读(以真值为条件的正确率模型)/掩蔽放大/
  冷却乱滑/技能囤积/呼喊倾向/分心断网,全部随机判定用按实体 id 哈希的独立抽签
  (mulberry32 流会被刷怪座位轮转结构带偏,实测造成系统性镜像反转,已证伪)
- recorder.mjs:每人每局 events.jsonl 全量 + percept.md 感知转写 + 对局速览

研究档案 research/hunt-sim/:
- players/:10 人配置(LLM 亲笔)+策略自述+逐局去留决策+人设终评+退游者重访
- rounds/:v1 三轮(R0 教学+R1/R2 真人快速)+ v2 复测两轮,共 48 局全记录
- analysis/01-04:数值曲线/音频信息设计/协作社交/上手留存四视角报告
- synthesis.md(S1-S9 裁定)、metrics.md/metrics-v2.md(两版对比总账)、report.md(总报告)

v1 核心发现:10 人 3 轮 28 局 100% 胜率 26S/营地零损耗;击杀垄断(专家单人 30/39);
呼喊 3 次/28 局应答 0;N/S 前后判读仅 63/69% 可命中;四种退游死因
(失衡/社交真空/交互摩擦/观光无聊)→ 详见 report.md
2026-09-19 11:06:07 +08:00

20 KiB
Raw Permalink Blame History

02 · 音频信息流设计分析(Q2 方位判读 / Q3 信道拥挤)· Phase 2

视角:纯音频信息流——耳朵在每一秒能听到什么、能不能判读、被谁掩蔽。 数据:metrics.md(28 局总账)+ 4 份抽样精读转写(P02/P08 · R1-quick,P07 · R2-quick,P10 · R0-teach)+ P01/P02/P09/P10 终评。 硬约束(全程自检):R6 红线——方位信息永远由声像承载,语音不得报方位;语音资产每句重新 TTS 有成本。 改动面缩写:G = web/hunt/game.js,S = web/server/hunt-room.js,V = docs/design/23-hunt-voice-ids.md(含 tools/gen_voice_dual.py 两表一致铁律),D = docs/design/23-hunt.md 同步。

0. 总判断

信息流层面三个结构性断点,且互相放大:① 前后轴只有"音量 ×0.6"一条线索,且与距离档共用响度维度(混淆是数学上注定的);② 出击冷却 2.5s 对玩家是纯黑箱(666 次乱滑被拦,无一毫秒就绪信息);③ up/down 手势"有怪=出击、无怪=菜单/状态链"的语境折中,把方位判读弱点直接兑换成误触 UI 与语音轰炸。R1-R8 机制本身全部成立(无叠播、无超限),但 R2 的"占线丢弃"打在唯一正确的时机上(波始),bot 喊话在快速局近乎绝迹。掩蔽的代价不在判读准确率(10% vs 10%,无差异),而在漏检与迟到——当前指标没有这个口径,复测需补。


A1 · 前后轴(N/S 家族)判读 63-69%:单线索、且与距离轴共维度

现象(数据+转写引用)

  • 混淆账(821 次登记,按 90° 弧可命中口径):N 63%(n=120)/ S 69%(n=85),而 E/W 100%、四斜向 96-99%。弱点严格落在 "pan=0、只能靠音量分前后" 的家族;N 同时是尝试量最大的桶(玩家默认往前滑)。
  • 转写翻车样本(全部是前后翻转,不是左右混淆):
    • P02 R1 00:45.7「以为左前实在正左」、01:11.4「上滑出击→以为正前的狼(其实在正后)」、01:18.9/01:44.7「以为正后(其实在正前)→下滑变菜单」;
    • P07 R2 01:44.2「以为正前其实在正后」、01:51.3「以为左前其实在正前——挥空」;
    • P10 R0 01:53.9「闷声以为左前,实在左后」、02:29.1「以为右后,其实在正前」。
  • 终评三方盖章:P01(资深,斜向混淆 <8% 的人设)「单音量线索在旁白轰炸下等于无线索」;P02「三局五验同判不同果,等于不可用」;P10「三局了这条规则从没进过我脑子」。

根因(三层,一层比一层深)

  1. 几何层:pan = sin(az),N/S 同为 0——StereoPanner 前后同位是已知物理边界,设计已用 ×0.6 补偿;但 -4.4dB 是一个响度差。
  2. 维度混淆层(设计根源):距离三档 0.30/0.55/0.80 与前后系数 ×0.6 共用同一个响度维度,且量级相当(档间差 -5.2dB / -3.2dB vs 前后差 -4.4dB)。具体对撞:前方中档 0.55 vs 后方贴脸档 0.80×0.6=0.48——差 0.5dB,人耳不可分;后方中档 0.33 与前方远档 0.30 直接重叠。"多远"和"前还是后"两个信息轴被压进同一根响度刻度,这不是练不练的问题,是解码不出来。
  3. 实现与教学层:
    • game.js _ensureMobLoop 里"闷"= vol × 0.6 纯增益(G:961),没有任何低通滤波——设计词面"身后发闷"承诺的是音色,实现只给了响度;
    • 教学零覆盖:hunt-room.js tickTeach 的教学狼全在前半平面(stage1 dir:'N'、stage2 N+NE,S:591/606-607),tut_rule 台词不含闷约定(voice-ids 头注写"由音效演示承担"——演示狼根本不从身后来)。P10 终评 P0-1 原话:「闷=身后零教学」。

修复提案(全部不越 R6 红线:方位仍由声像/音色承载,无语音报方位)

# 修法 机制/参数 改动面 新台词?
F1 后半平面低通第二线索(音色轴) loop 链路 src→gain→BiquadFilter(lowpass, f≈900Hz, Q≈0.7)→panner→sfxBus,后半平面启用、前半平面直通;与 ×0.6 音量并行。音色与响度正交,距离档不再污染前后判读。loop 走游戏层自建节点(abyss 先例),不动引擎面 G(_ensureMobLoop) 否
F2 前后系数加深 ×0.6→×0.5(-6dB),配合 F1 后响度只做辅助确认 G(一行常量)+D §8.3 同步 否
F3 教学补"身后"课 T1 杀掉 N 狼后补放一只 dir:'S', eta:12 教学狼(同样零惩罚、可挥空重教 ≤2 次);新台词点破:tut_back「这一声发闷——它在身后。声音发闷,就在背后。」;同时换写既有 tut_rule:「野兽会从八个方向围上来。声音在哪边,就往哪边滑。听着发闷的,在身后。」(重生成,不加 id) S(tickTeach)+V(+1 id) 是:新增 tut_back 1 id ×2 性别;tut_rule + key 变体各重生成 ×2。预算说明:旁白 60 句已打满,+1 需设计裁决(扩到 61,或砍 1 句低价值句腾位;候选:st_wave_c「最后一波了」与 wave_band5 语义重复度最高,但状态链在用——建议直接扩容并更新 D §10.3/自检 #5 口径)
F4 挥空增亮反馈(错向的真话由声像自己说) ev miss 后 0.3s 内,把当前内圈 eta 最小怪的 loop 短暂增亮 0.6s(vol×1.3;若在身后,这 0.6s 暂时解除低通)——玩家当场听到"真实方位",形成前后轴的即时纠错学习回路 G(_onMiss → _highlightNearest) 否
F5 (P2 备选)呼啸 howl 同样加低通 howl 走引擎 opts.pan one-shot,插滤波需引擎面例外——与 §9"引擎改动唯一一处"冲突,暂缓;外圈损失由中圈 loop(已带 F1)接管 (引擎例外,暂缓) 否

预期指标变化

  • N/S 可命中率 63%/69% → ≥85%(R4 同口径复测);斜向 96-99% 与 E/W 100% 不回归(F1 不动 pan)。
  • 前后翻转型挥空(转写归因"以为前/其实在后"类)样本占比下降 ≥60%;P02 类"同判不同果"主观报告消失(F1 使线索可解码,F3/F4 使其可学习)。
  • P10 类新手「闷声判反两次」→ 教学局内至少一次正确应对身后世狼。

A2 · 冷却黑箱:666 次乱滑被拦,就绪状态零外显

现象

  • 全场 666 次冷却乱滑被拦;P07 R2 一局 138 次(01:48.3-01:49.7 十一连滑、02:21.1-02:22.7 又十余次,每 100-300ms 一记 error 震,间夹 threat 重听);P09 三局局局「回神头两秒全在吃震」,P10「三局从没数清过一次冷却」「一度以为是我滑法不对」。
  • 实现现状(G):_attackDir 冷却内 vibrate('error'); return;——2.5s 冷却没有任何音/震/节拍外显;旋风斩 8s 有 skill_ready 语音,但 queue:true 排队在拥挤信道里迟到:P07 R2 02:25.3 战斗最烈时排不上,02:32.7 局已进入结算才播出来(_enterEnd 未清 _skillReadyTimer,跨局泄漏,bug 级)。
  • 附带偏差(需核查):P02 R1 00:37.2/00:38.1/00:39.0 三次被拦右滑,转写播了 gd_invalid「这个操作现在用不上」——设计口径是"冷却仅 error 震、gd_invalid onceKey 同局 1 次"。sim 感知模型与 game.js 两处不符(或真实客户端存在异常路径),实施前先对 harness 复刻核对。

根因

就绪状态只存在于客户端 _atkReadyAt 时间戳,没有任何模态把它交给耳朵/手掌;error 震语义是"不行"而不是"还差多久";冷却被拦与无效手势用同一种震(P10 三局分不清是冷却还是手势错);skill_ready 绑在语音队列上,信道越挤越迟到。

修复提案

# 修法 机制/参数 改动面 新台词?
F6 出击就绪双信号 冷却到期播 0.2s 合成短音 atk_ready(SYN 高频双 blip,中央,vol 0.5,R5 合规 <1s)+轻触觉(vibrate('confirm'))。节流:仅当本冷却窗内发生过被拦尝试才播(没人急着出手时不出声,避免每 2.5s 空响成噪声) G(_attackDir 内 arm setTimeout,复用 _armSkillReady 模式)+1 条程序合成 sfx 否(SYN 无 TTS)
F7 被拦反馈分级 同一冷却窗内首次被拦:专用触觉模式(0.4s 双脉冲,与"无效手势"单短震区分);第 2 次起合并静默至窗尾(消灭 P07 式连震风暴)。冷却与无效手势两种 error 从此可分辨 G(_attackDir + _invalid) 否
F8 skill_ready 去语音化+修跨局泄漏 改合成 earcon(上行双音 0.3s)+success 轻震;_enterEnd/_teardownRound/stop 一律清 _skillReadyTimer;skill_ready 语音 id 保留给 TEACH 讲解用 G(_armSkillReady、_enterEnd)+1 条 SYN sfx 否
F9 (P2 可选)冷却进度 tick 被拦时按剩余时间给 1-3 声短 tick(P02 要的"还差半秒");有 F6 后收益边际化 G 否

预期指标变化

  • 冷却乱滑被拦 666 → ≤200(就绪可听后 spam 自熄:P07 类玩家的连滑在第一声 ready 后失去动机)。
  • P09「回神头两秒吃震」消除;P10「扣的那 1 分」收回;skill_ready 跨局/迟到播报归零(语音打断 37 次中 skill_ready 相关子项清空)。

A3 · down/up 双语义陷阱:误触菜单与状态链误播

现象

  • 下滑=菜单误触,6/10 玩家中招:P01 R1 连环 14 次(终评:「下滑退出和下滑打正后是同一根手指,三次下滑全弹回菜单」);P07 R2 01:15.6-01:17.6 菜单乒乓 6 轮(每轮 sys_menu→回到猎场→settings_hint 三句链互相打断,"回到猎场"四度播不完);P02 R1 五次(01:18.9/01:44.7/02:20.9-02:21.3 连环);P08 R1 三次;P09 三局同坑(进菜单后 01:09.3 盲单击又误触"重新听帮助")。
  • 上滑=状态链误播:错向挥出的上/下滑恰好制造"弧内无怪"→ 变成播报。P02 R1 01:11.4「以为正前其实在正后→上滑变成 4 句状态链」;P07 R2 01:44.2 同型。状态链 4 句 ≈5-6s 占满语音通道(见 A4)。
  • 菜单打开战斗照走(E3 豁免本意),P01 终评 P0-1 定性:「操作本身就是在跟系统打架」。

根因

23-hunt §2.1 表格自身双重定义(四向滑=出击 vs 上滑=状态链/下滑=菜单);game.js 文件头"语境折中"用 _arcHasTarget()(客户端本地、eta≤4、事件流瞬时空窗都影响判定)做分流——把"打不打得到"这个毫秒级动态事实当作"出招还是开 UI"的开关。且误触率与 A1 前后弱点正相关:错向 → 无怪 → 菜单。退出菜单仍是下滑,同一根手指解自己上的锁。

修复提案

# 修法 机制/参数 改动面 新台词?
F10 WAVE 态下滑恒=出击 无目标也走完整出击:atk_whoosh+服务器 miss → atk_swish 真话+error 震(与左/右滑同待遇)。菜单入口改为:①波间休整(wave_clear 后 8s 窗)内下滑=菜单;②战斗中长按=菜单(WAVE 态旁白极少,快进让渡成本最低——需宪法裁决登记 E3 修订);若裁决不动长按,则战斗中无菜单、退出只在波间 G(_onWaveGesture)+D §2.1/§2.4/§2.5 豁免表同步 否
F11 上滑状态链两条护栏 ①链播中再上滑=立即停止(现在会再排 4 句,P02 R0 23 秒里"营地固若金汤"五遍);②危急截断:任一怪进入贴脸档(eta<2.5s)时,正在播的状态/菜单/帮助/watchdog 链立即截断(_chainSeq+++stopVoice;警报/教学/结算链豁免)——即 P02 点名的"危急时刻静默通道",实现"loop 优先"而不动引擎 ducking G(_statusChain、_refreshLoops 内挂钩) 否
F12 状态链瘦身 4 句→按变化播:耐久档+击杀档恒播;波次档仅波次变更后首次播;猎人数仅 roster 变更后播(P08 是状态链重度用户且终评正向——保留主干只砍复读) G(_statusIds) 否

预期指标变化

  • 战斗中 menu-open 误触:P01 的 14 次/局 → 0(结构性消除)。
  • 语音打断 37 → ≤15(大头是菜单乒乓互切,见 A4 清单)。
  • "状态链压贴脸脚步"型掩蔽案例(P02 R2 01:21.0-01:26.8)归零;P01 P0-1/P0-2 直接收口。

A4 · 语音通道 × 战斗信息冲突账

掩蔽源清单(按占用时长与伤害排序;样本来自 4 份精读转写)

源 单次占用 样本频次 价值裁定
误触菜单链(sys_menu+sys_menu_resume+settings_hint) 3 句 ≈5s P02 R1 ×5、P07 R2 菜单乒乓期近连续、P08 R1 ×3 负价值;F10 后归零
help_main 战斗中整播 ≈8s P08 R1 01:33.4/02:02.3、P07 R2 01:40.9、P01 R1 ×2 负价值(P01:「对老手重播基础教学=战斗中没收我的耳朵」);F10 后结构性消失(菜单不在战斗态)
状态链 4 句 ≈5-6s P08 R1 主动使用 ×6;P02 R0 23s 五遍复读 中价值(P08/P06 靠它感知战局)——瘦身保留(F11/F12),不删功能
watchdog 两级(idle 提示音+gd_idle) ≈2s×2 全场 93 次 ≈3.3 次/局;P10 R2 七次全误伤(在等怪不是挂机) 救命索但触发条件错(P09 走神 9 次全被拽回)。修:inner-ring 有怪、或 5s 内有击杀/被拦/呼喊记录时不触发;第 1 级降为纯震+短音,第 2 级才上语音(G _rearmWatchdog 条件)
波次/威胁/警报(wave_band*/threat_*/breach*) 各 1 句 合法占用 警报可达性 PASS:28 局 6 次 breach 全部按时到达并正确顶掉状态类(R1 实测有效);threat_* 重听是 P07 的双击主出口,属宪法语义,保留
skill_ready 1 句 P07 R2 高频 F8 去语音化后退出竞争

掩蔽 × 误判的诚实读数

metrics:掩蔽下误判率 10%(n=297)vs 干净时 10%(n=524)——判读准确率不受掩蔽影响(拟人模型"听到后"的判读与掩蔽无关)。但掩蔽的真实代价是漏检/迟到:P01「menu 播报正好盖掉右后闷脚步→四连打空」、P02「状态链四句压着贴脸脚步」。当前混淆账不测这个。复测新增指标:「掩蔽窗漏检率」=语音在播期间进入内圈的怪,玩家首次针对性出手延迟 >1.5s 的比例(基线值 R4 复测时先量再比)。

bot 喊话饿死(结构性对撞)

  • R2 客户端规则"旁白在播→延迟 ≤2s→丢弃",撞上服务端触发时机:greet 排在开局(GREET_FIRST_MS 起,S:352-353)、wave 排在波始(S:371)——这两个时刻旁白必播(room_start+wave_band1 / wave_bandN),氛围句 2s TTL 必死。
  • 实测:P10 R0 教学局 12 条 botline 中 7 条被挤掉(00:04.6 greet、01:07.3/02:11.5/02:43.1 恰为波始),5 条可闻(help_call/help_ack/cover/kill×2——priority 句 4s TTL 兑现了"呼救不可被顶");P02/P07/P08 三份快速局转写可闻 bot 喊话 0 条。
  • 注意另一根因:P01 R1 是 4 真人房(0 bot),bot 喊话结构性为零——"真人房社交声道缺失"要靠呼喊链路补(全场呼喊仅 3 次/28 局,且 P02 R1 02:12.6 呼喊的本地反馈在转写里呈现为旁白"重新听帮助。",同房 P01 也没报告听到空间化喊话——呼喊播放链路需专项核查)。

修法 F13(S+G,无新台词):服务端 wave/greet botline 延迟 3.5s 投递(等 wave_band 播完;BOTLINE 预算 10s≤2 不变);客户端非优先句 TTL 2s→4s。预期:快速局人均可闻喊话 0→3-5 条;教学局挤掉 7→≤2。


A5 · R1-R8 拥挤规则在真实并发下的表现

规则 机制是否成立 真实并发下的表现与裁定
R1 旁白单句队列 ✅ 全程无叠播;警报顶状态类实测有效(breach 到达 6/6)。代价=队列拥堵与打断(37 次,主因菜单乒乓,F10 后大减);发现的 bug:skill_ready 排队跨入结算链(P07 R2 02:32.7),F8 修复
R2 喊话 sfx ≤1+延迟丢弃 ✅(但丢弃打错时机) 上限无违例;丢弃全落在 greet/wave 两类"旁白必播时刻"——修触发时机(F13),不放宽 ≤1 上限。help_call/help_ack 优先级兑现(教学局 5 条可闻里 3 条是 priority)
R3 loop ≤3 路 ✅ 且无害 无"第 4 近怪因静默突入"的可归因案例(快速局 6 局全零 breach);被裁剪怪的方位由击杀倒地音(带 pan)部分补偿。维持原样
R4 one-shot ≤2+呼啸可弃 ✅ 波 4-5 生成潮确有呼啸被弃(外圈方向预告缺失),但中圈起 loop 接管,本数据集无可归因损失。可选微调 HOWL_QUEUE_MAX 2→3 / TTL 1.5→1.2s——收益小,列 P2
R5 非语音 <1s ✅ 无违例
R6 方位由声像承载 ✅ 全程无语音报方位。这是立身之本:本报告所有修法(低通/增亮/earcon)均让声像自己说话,明确拒绝"语音报前后"类越线捷径
R7 电平分层 ⚠️ 半成立 BGM duck 语音方向正确;但"语音 vs loop"无互让——用 F11 危急截断在游戏层实现"贴脸 loop 优先",不动引擎
R8 ≤7 声流 ✅ 转写无超限/叠爆证据

修复优先级表

级 编号 修法 改动面 新台词(TTS 成本) 预期指标
P0 F1 后半平面 loop 低通(音色第二线索) G 否 N/S 63/69% → ≥80%(配合 F3 冲 ≥85%)
P0 F6 出击就绪 earcon+触觉(有被拦才播) G+1 SYN sfx 否(程序合成) 乱滑被拦 666 → ≤200
P0 F10 WAVE 下滑恒出击;菜单改波间窗/长按 G+D(E3 修订) 否 战斗中误触菜单 →0;语音打断 37 → ≤15
P0 F3 教学补身后期:S 向教学狼+tut_back+tut_rule 换写 S+V 是:+1 id×2 性别;tut_rule(含 key 变体) 重生成 ×4;60 句预算需裁决扩容 新手前后翻车率减半;「闷」从零教学变一课学会
P1 F11 危急截断+链中再上滑即停 G 否 状态链压贴脸脚步案例归零
P1 F7 被拦反馈分级(冷却≠无效手势,连震合并) G 否 P10 类"自我怀疑"消除
P1 F13 botline 波始延迟 3.5s+客户端 TTL 2→4s;呼喊链路专项核查 S+G 否 快速局可闻喊话 0→3-5 条/人
P1 F8 skill_ready 去语音化+局末清 timer G+1 SYN sfx 否 跨局泄漏/迟到归零
P1 F12 状态链按变化播(4 句→2-4 句) G 否 "固若金汤"复读投诉归零,状态感知功能保留
P2 F4 挥空增亮(0.6s 突出真方位 loop) G 否 前后错向即时纠错学习回路
P2 F2 前后系数 0.6→0.5 G+D §8.3 否 F1 的响度辅助确认
P2 F5/F9 及 watchdog 降级、HOWL 队列微调 见 A4/A5 G/S 否 边际改善

汇总账:12 项修法中仅 F3 需要新台词(1 个新 id + 1 个既有 id 换写重生成,合计 6 条 TTS:tut_back×2 性别、tut_rule×2 性别+key 变体×2);其余全部是 game.js / hunt-room.js 逻辑与程序合成 sfx,零 TTS 成本。全部修法通过 R6 红线自检(无一句语音报方位)。

复测口径提醒(给 synthesis):①混淆账同口径重跑(N/S 家族单列);②新增"掩蔽窗漏检率";③新增"战斗中 menu-open 次数""被拦后至就绪出手的中位延迟""bot 喊话可闻条数/人/局";④先核对 sim 感知模型两处偏差(冷却被拦播 gd_invalid、呼喊本地反馈异常),确保 R4 对比不被 harness 噪声污染。