249 lines
28 KiB
Markdown
249 lines
28 KiB
Markdown
# 14 · 向导交互层设计裁定(v1 基线)
|
||
|
||
> 依据:research/02-methodology/methodology.md §3(L3 状态层 / L4 引导层)→
|
||
> research/03-schemes/schemes.md §1/§2(实施蓝图,唯一事实源)。
|
||
> 本文存档 v1 已落地的裁定与新增语音资产台词表,供后续轮次回溯。
|
||
> 实现载体:`web/engine/guide.js`(引擎向导模块)+ 各游戏 game.js 接线。
|
||
|
||
## 1. 裁定摘要
|
||
|
||
| # | 裁定 | 内容 |
|
||
|---|---|---|
|
||
| 1 | 分期 | v1 只做「全局基线」= 引擎向导层 + 逐游戏接线;场景参数包(A 通勤/B 摸鱼/C 睡前/D 下班)与人设旋钮在试玩验证后分期(schemes §3)。 |
|
||
| 2 | 等级 | `settings.guide`:`'full'`(默认,earcon+语音+震动)/ `'standard'`(earcon+震动,无语音)/ `'off'`(全静 no-op,**不挂任何定时器**)。大厅设置面板「向导帮助:详细/只听提示音/关闭」。 |
|
||
| 3 | earcon | 8 个签名(6 状态 menu/explore/battle/choice/settle/danger + 2 功能 turn/nudge)**全项目统一**,全部运行时 WebAudio 合成(零资产、可复现);总长 0.25~0.4s、单音 ≥0.08s、125Hz~5kHz、总增益 ≈0.12;家族=波形音色、子类=节奏轮廓(schemes §1.4)。 |
|
||
| 4 | 语音纪律 | 向导插播语音一律 `queue:true`(等当前对白播完),**绝不顶掉正在播的内容**;抉择提示(storyline p*)播完即可选的等待点不插任何语音。 |
|
||
| 5 | 看门狗 | 统一模板:静默 N 秒 → nudge 轻 earcon(+ full 档语音)→ 二次升级播上下文提示 → 级数用尽自动停止;任何手势/向导动作复位。escape 的三级卡关骨架保留,仅加「连续撞墙 ≥2 次 → full 档阈值提前一级」。 |
|
||
| 6 | 引擎配套 | `audio.isVoicePlaying()` 公开只读 API(收编 5 处私有 `_voice` 读);`audio.setRateBoostEnabled(bool)` 长按快进 per-game 开关(rhythm/space 对局期豁免);`settings.speed` 增加 2.2 档(视障档,250+ WPM)。 |
|
||
| 7 | 语义分工铁律 | 语音说「你要做什么」、earcon 说「哪类事/哪个状态」、BGM 说「宏观状态」、震动说「刚才那下对不对」——向导层不越界(L2 铁律:earcon 只做粗标记,语义靠语音)。 |
|
||
|
||
## 2. 逐游戏接线裁定(v1 落地范围)
|
||
|
||
| 游戏 | 接线 |
|
||
|---|---|
|
||
| storyline | W1/W3 静默看门狗 [8s]=nudge+`gd_continue`、[20s]=复用 `playHelpAndResume`;选择节点外左右滑的静默 return 处加 error 震+`gd_invalid`;抉择态(p* 播完)不插语音不挂看门狗;状态签名 explore/menu 与状态 BGM 同点。 |
|
||
| simon | input 看门狗 [10s]=nudge+`gd_relisten`、[25s]=免扣机会自动重听(每局 2 次);`your_turn` 泛化为 turn earcon(每轮,第 1 轮保留原语音);状态签名 settle/menu。 |
|
||
| escape | REOPEN 提示播完与引导步解锁给 turn cue;连续撞墙 ≥2 次 → full 档卡关三级阈值提前一级;其余(wrong/blunt/stuck/nav)保持既有完备体系。 |
|
||
| rhythm | 每曲首次领奏→应答切换推 `gd_answer`(谱面排程处入 `_timed`);连续 2 Miss 播 `gd_miss`(queue 插播,同曲一次);结算链换 `_speakGuarded`;main 演奏期 `setRateBoostEnabled(false)`;状态签名 menu/battle/settle。 |
|
||
| space | 对局第 1 次受击(保护期外)追加 `gd_hit_hint`;结算链换 `_speakGuarded`;对局期 `setRateBoostEnabled(false)`;状态签名 battle/menu/settle。 |
|
||
| rpg | 格挡窗口内做错手势 → error 震+`gd_parry_miss`(每局一次);PLAYER_SELECT 挂看门狗 [60s]=nudge+`gd_stall`;状态签名 explore/battle/menu/settle 与四状态 BGM 同点补齐。 |
|
||
|
||
## 3. 新增语音资产台词表(8 句 ×2 性别 = 16 文件)
|
||
|
||
定稿依据 schemes.md §1.5,台词全文一字不改;speaker/instruct 沿用各游戏旁白常量
|
||
(见 `tools/gen_voice_dual.py` SPEAKERS 与各 `_XXX` pair):
|
||
|
||
| 游戏 | id | 全文 | 触发 | female speaker / instruct | male speaker / instruct |
|
||
|---|---|---|---|---|---|
|
||
| storyline | `gd_continue` | 轻触屏幕,继续。 | W1/W3 叙事节点播完静默 8s(看门狗第 1 级) | Vivian / _SL_NARR[1] | Uncle_Fu / _SL_NARR[0] |
|
||
| storyline | `gd_invalid` | 这个操作在这里用不上。 | 无效手势(选择节点外左右滑静默 return,同局限次) | Vivian / _SL_NARR[1] | Uncle_Fu / _SL_NARR[0] |
|
||
| simon | `gd_relisten` | 需要的话,双击可以重新听一遍序列。 | input 阶段 10s 无输入(不改变重听扣机会规则) | Serena / _SIMON | Uncle_Fu / _SIMON |
|
||
| rhythm | `gd_answer` | 现在跟着我打。 | 每曲首次领奏→应答切换 | Vivian / _RHY | Uncle_Fu / _RHY |
|
||
| rhythm | `gd_miss` | 慢了半拍,下一小节跟上我就行。 | 连续 2 次 Miss(同曲限 1 次,queue 插播) | Vivian / _RHY | Uncle_Fu / _RHY |
|
||
| space | `gd_hit_hint` | 被撞了。听方位,同向滑动就能拨开。 | 对局第 1 次受击(保护期外,同局 1 次) | Serena / _SPC | Uncle_Fu / _SPC |
|
||
| rpg | `gd_parry_miss` | 前摇声起的时候双击,才能格挡。 | 格挡窗口内做错手势(每局限次) | Serena / _RPG | Uncle_Fu / _RPG |
|
||
| rpg | `gd_stall` | 想好了吗?左右滑动选择,单击出手。 | PLAYER_SELECT 60s 无输入 | Serena / _RPG | Uncle_Fu / _RPG |
|
||
|
||
资产落位:`web/<game>/audio/voice/{female,male}/gd_*.{ogg,m4a}`(管线
|
||
`tools/gen_voice_dual.py --game <g> --only gd_xxx` 生成 + `--convert` 落盘,
|
||
双格式配对由 `tools/check_all_assets.py` 终检保证)。
|
||
|
||
## 4. 已知边界与后续候选
|
||
|
||
- `onceKey` 语义为「同局(游戏会话)一次」;schemes §1.5 中 storyline `gd_invalid`
|
||
「同局限 2 次」、rpg `gd_parry_miss`「每场战斗 1 次」为更细粒度限次,v1 统一收敛到
|
||
onceKey(一次教学提示足矣),如试玩反馈不足再引入 per-run 限次 API。
|
||
- 教学义务(schemes §1.4「full 档开场教学带教签名 earcon」):v1 未在各游戏教学链中
|
||
逐个口播签名音,列为 v2 候选(需逐游戏改教学台词,涉及台词表返工)。
|
||
- 向导插播语音目前挂在引擎 voice 队列;若游戏层 `stopVoice()` 会顺带丢弃排队中的
|
||
向导句(作废语义,可接受)。
|
||
|
||
---
|
||
|
||
# 14 · 向导交互层设计裁定(round2 v1.1 增补)
|
||
|
||
> 依据:research/04-playtests/round1/synthesis.md(F1~F9 + §3 新语音表,唯一事实源)。
|
||
> 本文只做**追加**,上文 v1 基线裁定不回改;实现载体同 v1(`web/engine/guide.js`
|
||
> + 各游戏 game.js 接线),全部改动已落地。
|
||
|
||
## 5. round2 裁定落地摘要(F1~F9)
|
||
|
||
| # | 裁定 | 落地 |
|
||
|---|---|---|
|
||
| F1.1 | storyline 看门狗礼仪 | at `[8s,20s]`→**`[25s,50s]`**;say `[gd_continue, gd_again]`;**删除升级重播 help+进度+当前节点的 `playHelpAndResume` 逻辑**(`_guideHelped` 一并移除);两级用尽彻底静默(引擎既有)。 |
|
||
| F1.2 | simon 25s 升级去泄题 | **取消免扣机会自动重播序列**(`_guideAutoRelisten`/`GUIDE_AUTO_RELISTEN_MAX` 删除)→ 改为 `guide.turn({haptic:true})`(confirm 震 + turn earcon,纯标记无语音)。 |
|
||
| F1.3 | rpg PLAYER_SELECT 看门狗 | 60s→**30s**(`gd_stall` 不变)。 |
|
||
| F1.4 | 空闲才播(idle-only) | `guide._say` 对 **error / watchdog** 两类:`audio.isVoicePlaying()` 为 true 时**跳过语音只发事件(事件带 `skipped:true`)**——修「纠错句排到语音链尾迟到误导」;**turn 保持 queue 不变**。error 的 onceKey 只在语音真的播出时才计数(没听到不算说过)。space 的 `gd_hit_hint`/`gd_last_life` 接线点随之外移到受击归因链播完后的空闲点,否则会被自家归因句判为「在播」整段跳过。 |
|
||
| F2.1 | rhythm 教学首次归因 | 教学步**首次失败**即在纠正链(retry_* + retry_listen)播完后的空闲点发分档句:方向错 `gd_miss_wrong` / 抢拍 `gd_miss_early` / 慢拍 `gd_miss_late`;判定沿用 `_tutAttempts`(手势错 > dt<0 > dt>0),**无窗内尝试(没出手)归入 `gd_miss_late`**;第二次失败走 retry_skip 不再叠加归因。正片连 2 Miss 仍用 `gd_miss`。 |
|
||
| F2.2 | space 受击经济透明 | 第 2 次受击在 `hit_<dir>`+`hit_last` 链播完后发 `gd_last_life`(见 F1.4 接线点说明)。 |
|
||
| F2.3 | escape 撞墙报方位 | 撞墙在既有 `voice/wall` 播完后接既有 `guide_blunt_<dir>` 方向句(资产 v1 已有,纯逻辑接线;被下一次移动打断则自然作废)。全档位生效(游戏反馈层,非 full 档专属)。 |
|
||
| F3.1 | rhythm 交接提前 | `gd_answer` 不再走 guide 的 queue——由 `guide.turn({})` 发 turn earcon、语音由**曲谱定时队列**(`_timed`,首个应答窗口前一小节头)在 full 档直接落下,保证窗口前听到。 |
|
||
| F3.2 | 断点续播 count-in | 暂停菜单恢复时网格/BGM 整体后移一小节,前 4 拍用底鼓(`inst_kick` 0.7)+beat 轻震做 count-in(走既有 `_sched` 网格排程);**off 档保持原即时续播**(零改动路径)。 |
|
||
| F4 | rpg 教学看表现 | T2 格挡**成功**通过时插 `tut_b2b`「挡得漂亮。」再进 T3;失败路径(tut_b4)不变。 |
|
||
| F5 | simon 经济透明 | 教学收尾链改为 t7_ready→t7_retry→**`gd_economy`**→开局(guard 12s→20s)。作为游戏规则句随教学链播(全档位),与 skip_hint 同类。 |
|
||
| F6 | space 警报叠爆 | 警报音效按 soft/loud 两档各自 **600ms 窗口去重**(双陨石同时逼近只起一波渐强警报,单颗两段渐强不受影响);danger 震全局限 **≥400ms** 间隔。 |
|
||
| F7 | rpg 菜单回绕 | 探索选项列表与战斗指令循环:右滑回首项→`gd_wrap_first`、左滑到末项→`gd_wrap_last`;full 档 queue 跟在本项报名之后,**同一次菜单打开内每句最多 1 次**(`_wrapShown` 在进场景/进入玩家回合时重置);被下一次滑动打断则自然作废。 |
|
||
| F8 | storyline 开场瘦身 | 开场链最前插 `gd_brief`(full 档,brief→intro);intro 长句资产保留不动。 |
|
||
| F9 | 语速演示 | round2 会话剧本在 storyline 段演示 `settings.speed=2.2` 切换(转写可见),产品代码零改动(v1 已支持)。 |
|
||
|
||
## 6. round2 新增语音资产台词表(10 句 ×2 性别 = 20 文件)
|
||
|
||
全文与 synthesis §3 逐字一致;speaker/instruct 沿用各游戏旁白 pair 常量:
|
||
|
||
| 游戏 | id | 全文 | 触发 |
|
||
|---|---|---|---|
|
||
| storyline | `gd_brief` | 单击继续剧情。请选择的时候,左右滑动。 | 开场链最前(F8,full 档) |
|
||
| storyline | `gd_again` | 还在吗?单击继续。 | 看门狗 50s 升级(F1.1,替代重播 help) |
|
||
| rhythm | `gd_miss_early` | 抢拍了。等声音落下再滑。 | 教学 Miss 且抢拍(F2.1) |
|
||
| rhythm | `gd_miss_late` | 慢了半拍。跟着节拍走。 | 教学 Miss 且慢拍/没出手(F2.1) |
|
||
| rhythm | `gd_miss_wrong` | 方向不对。跟着音色滑。 | 教学 Miss 且手势方向错(F2.1) |
|
||
| simon | `gd_economy` | 记不住就双击重新听,免费机会有两次,用完要扣一次机会。 | 开局教学末尾(F5,全档位) |
|
||
| space | `gd_last_life` | 这是最后一次机会,撑住。 | 第 2 次受击(F2.2,归因链后空闲点) |
|
||
| rpg | `tut_b2b` | 挡得漂亮。 | 教学 T2 格挡成功(F4,全档位) |
|
||
| rpg | `gd_wrap_first` | 回到第一个。 | 菜单/指令循环切回首项(F7,full 档) |
|
||
| rpg | `gd_wrap_last` | 最后一个了。 | 循环切到末项(F7,full 档) |
|
||
|
||
## 7. round2 验证记录
|
||
|
||
- 6 playtest(guide=off):**断言零改动全绿**(storyline 54 / escape 103 / simon 108 /
|
||
rhythm 81 / space 113 / rpg 139,与 v1 基线一致)。
|
||
- `web/harness/guide.test.mjs` 52 断言全绿:storyline 25s/50s 新节奏 + 无重播断言、
|
||
simon 25s 无序列重播 + confirm 震/turn 事件、F1.4 idle-skip 直连断言(watchdog/
|
||
error 在播跳过 + 空闲播放 + turn 保持 queue)、off 档全静零定时器。
|
||
- `tools/check_all_assets.py` 全绿(双格式配对、无 0 字节、全可解码、双性别集合一致);
|
||
`tools/extract_voice_text.py` 已刷新 `web/harness/voice_text.json`(428 句)。
|
||
- 转写渲染适配:实际播出的 `voice/gd_*` 由 play 捕获照常渲染;被 idle-skip 的
|
||
向导句单独标注「本句按 idle-only 跳过未播」。
|
||
|
||
---
|
||
|
||
# 14 · 向导交互层设计裁定(round3 v1.2 增补)
|
||
|
||
> 依据:research/04-playtests/round2/synthesis.md(G1~G8 + §3 新语音表,唯一事实源)。
|
||
> 本文只做**追加**,上文 v1 / round2 裁定不回改;实现载体同前(`web/engine/guide.js`
|
||
> + 各游戏 game.js 接线),全部改动已落地。G8(不做项)照裁定书记录,不再列。
|
||
|
||
## 8. round3 裁定落地摘要(G1~G7)
|
||
|
||
| # | 裁定 | 落地 |
|
||
|---|---|---|
|
||
| G1 | rhythm「轮到你」迟到 bug | **根因诊断**:round2 F3 把 gd_answer 排在 `leadBarT0 + 4*spb`——那是首个应答窗口**起点本身**(领奏小节的末尾),不是窗口前;P4 转写(窗口 t+79~95、gd_answer t+93.7)即窗口开后才响,起不到预警作用。**修复**:排程点改到 `leadBarT0`(窗口前整整 1 小节 = 领奏小节头);`_armAnswerCue`/`_fireAnswerCue` 承接——菜单恢复也是一次「进 main」,旧标记已消费时对恢复后首个未判定窗口重排同款标记(已迫近则 0.15s 内尽早补上);上一句结束后的下一句不适用(裁定原文)。gd_answer 语音 full 档经曲谱定时队列直达(不走 guide queue),turn earcon **standard 也发**(off 全静不变)。guide.test 增转写级断言:真实跑 90BPM 一曲,gd_answer 时刻 < 首窗口起点,且窗口起点 − gd_answer ≈ 4×spb。 |
|
||
| G2 | rhythm 教学降难 DDA | 同一步连续 2 次失败 → 该步领奏**降速 25% 重演**(`_tutRate=0.75`:该步领奏与应答网格间隔 ×1/0.75,领奏小节头仍对齐 BGM 小节,BGM 不变速;排程照走 `_sched` 绝对时间 + 40ms 泵,泵与判定零改动)+ full 档先播 `gd_slow`「我放慢一些,跟着试试。」(经 `_speakGuarded` 串行,播完才重演);每教学局 1 次封顶(`_tutSlowUsed`);该步做对或离开(跳步)恢复正常速度;降速重演后该步重新给两次机会。**off 档维持 round2 的 retry_skip 跳步原路径**(6 playtest 断言零改动红线)。 |
|
||
| G3 | rhythm 恢复 count-in 可感知化 | **根因诊断**:round2 F3.2 的 count-in 排了但**从未按时响过**——底鼓 push 进 `_sched` 后没有重排,队头是数秒外的领奏音符,40ms 泵的 `LOOKAHEAD(0.6s)` 前瞻窗口永远轮不到队尾的 count-in(复现实测:恢复后 4 记底鼓与 beat 震全部迟到聚堆),P3 听到的正是「恢复后 5 秒死寂」。**修复**:push 后 `_sortSched()`;底鼓音量 0.7→**1.0**(sfx 层独立于 BGM,每拍 beat 震保持);full 档恢复时先经 `_speakGuarded` 播 `gd_count`「四拍之后,继续。」(每局恢复限 1 次,`_gdCountUsed`;链完/缺失兜底后才开始数拍);恢复用令牌 `_resumeSeq` 防 count-in 语音期间再开菜单的旧恢复串场。**off 档保持 v1 即时续播**(playtest 断言零改动红线)。 |
|
||
| G4 | escape 保险丝→新目标断链 | 拾取保险丝的 `unlock_cabinet`(关键获得不可跳)播完后接 `gd_next_fuse`「保险丝到手。接下来,去找电箱。」——游戏反馈层**全档位**(走游戏语音链不走向导通道,gd_economy 先例)。 |
|
||
| G5 | simon 双击双义根治 | **改全局规则**:input 阶段**双击永远=作答(第 6 音色)**——期望恰为 doubletap 判对,否则照常判错,不再承担重听;主动重听改绑**上滑**(期望输入恰为 up 时上滑=作答,六手势全是答题输入的 00 §5.3 豁免同款);非输入阶段行为不变。`gd_economy` 按裁定书新文案**重录**(记不住就向上滑…);教学第 6 音色步资产 `t6_double`「双击,是这个声音。」不含重听语义、无需改动,教学步与新文案不矛盾。**超出裁定书 §3 清单的同口径修正(2 句,见 §9 注)**:`gd_relisten`(input 看门狗提示)与 `t7_retry`(教学收尾链)旧文案都在教「双击重听」,不清掉等于保留 P0,随 G5 一并重录为上滑口径,台词改动仅「双击→向上滑」机械替换。 |
|
||
| G6 | simon 局尾反馈轻量化 | 每轮成功在既有轮结算链(`_roundClear` 的 correct/chance_plus 链)尾追加 `gd_clear`「漂亮,过了。」(每局 1 次);本轮完成数超过历史最佳且确有旧纪录(`best>0`)时追加 `gd_record`「破纪录了。」(每局 1 次;结算另有 new_record,此处是局中破纪录的即时一刻)。游戏反馈层全档位。 |
|
||
| G7 | space 方向呼喊第二通道 | loud 警报档(撞击前 500ms)回调里同窗直达播 `voice/dir_<dir>`「左!/右!/上!/下!」——与 sfx/alarm 分属 voice/sfx 两通道天然同时不互顶(引擎对白 duck 压 BGM 保证可闻);**直达式播放不排队**(呼喊必须赶在撞击前,宁可顶掉里程/充能类短句也不排到链尾迟到);游戏反馈层全档位。 |
|
||
|
||
## 9. round3 新增语音资产台词表(11 句 ×2 性别 = 22 文件;其中 G5 为重录 3 句)
|
||
|
||
全文与 synthesis §3 逐字一致(speaker/instruct 沿用各游戏旁白 pair 常量,dir_* 按表注
|
||
用 space 旁白 pair);另 2 句为 G5 手势映射的同口径机械修正(裁定书 §3 未列,落地
|
||
原因见 §8/G5——不清掉「双击重听」旧文案,input 看门狗与教学收尾仍在教已废除的手势):
|
||
|
||
| 游戏 | id | 全文 | 触发 |
|
||
|---|---|---|---|
|
||
| rhythm | `gd_slow` | 我放慢一些,跟着试试。 | 教学连 2 失败降速重演前(G2,full 档,每教学局 1 次) |
|
||
| rhythm | `gd_count` | 四拍之后,继续。 | 菜单恢复 count-in 前(G3,full 档,每局恢复限 1 次) |
|
||
| escape | `gd_next_fuse` | 保险丝到手。接下来,去找电箱。 | 拾取保险丝链尾(G4,全档位) |
|
||
| simon | `gd_economy`(重录) | 记不住就向上滑,重新听一遍。免费机会有两次,用完要扣一次机会。 | 开局教学末尾(G5,全档位) |
|
||
| simon | `gd_clear` | 漂亮,过了。 | 每轮成功链尾(G6,全档位,每局 1 次) |
|
||
| simon | `gd_record` | 破纪录了。 | 局中破个人纪录(G6,全档位,每局 1 次) |
|
||
| space | `dir_left` / `dir_right` / `dir_up` / `dir_down` | 左!/ 右!/ 上!/ 下! | loud 警报档方向呼喊(G7,全档位) |
|
||
| simon | `gd_relisten`(同口径修正) | 需要的话,向上滑可以重新听一遍序列。 | input 10s 看门狗(原「双击可以重新听」,G5) |
|
||
| simon | `t7_retry`(同口径修正) | 答错可以消耗机会重听。向上滑,可以随时重听。 | 教学收尾链(原「双击,可以随时重听」,G5) |
|
||
|
||
资产落位与管线同前:`web/<game>/audio/voice/{female,male}/<id>.{ogg,m4a}`
|
||
(`tools/gen_voice_dual.py --game <g> --only <id>` 生成 → `--convert` 落盘 →
|
||
`tools/check_all_assets.py` 终检)。
|
||
|
||
## 10. round3 验证记录
|
||
|
||
- 6 playtest(guide=off):除 simon 按 13 号文档 round3 变更记录改口 3 处断言
|
||
(input 双击=作答、上滑=重听;108 条总数与 round2 基线一致)外,**断言零改动
|
||
全绿**:storyline 54 / escape 103 / simon 108 / rhythm 81 / space 113 / rpg 139。
|
||
- `web/harness/guide.test.mjs` **93 条断言全绿**(round2 基线 52 条既有断言零改动,
|
||
其余为新增):G1(gd_answer 时间窗=窗口前整整 1 小节、恢复后重排仍在窗前)、
|
||
G2(连 2 失败降速 ×1/0.75 + gd_slow + 做对恢复 + 每局封顶后回退 retry_skip)、
|
||
G3(恢复先 gd_count 后 count-in、底鼓重排入队头、beat 震、每局限 1 次)、
|
||
G5(双击作答/上滑重听/期望恰为 up 时上滑=作答,full 与 off 双档)、
|
||
G6(gd_clear 每局 1 次 + 破纪录 gd_record)、G7(dir_* 与 loud 警报同窗 ≤50ms)。
|
||
为此给 harness mock 补了 setInterval/虚拟 ctx.currentTime/用例间 localStorage 隔离。
|
||
- 转写 harness 修复(`web/harness/mock.mjs`,工具层非玩法):decodeAudioData 原来
|
||
按「最近一次 fetch 的 url」估时长,prewarm 并发下 voice 会随机继承 bgm 的 90s
|
||
时长,语音结束定时器形同虚设(链全靠兜底看门狗推进、教学 tap 被滞留语音当跳过
|
||
吃掉)——改为按 ArrayBuffer 自身 `__url` 估算,与各 playtest mock 对齐。
|
||
- `tools/check_all_assets.py` 全绿(双格式配对、无 0 字节、全可解码、双性别集合
|
||
一致);`tools/extract_voice_text.py` 已刷新 `web/harness/voice_text.json`
|
||
(437 句)。`gen_voice_dual.py --check` 中 rpg/tut_b0 等 4 句「缺 staging」为
|
||
R5 既有已知项(资产已先行落盘、staging 无 wav),非本轮引入。
|
||
- 转写抽查(research/04-playtests/transcripts/,6 份全部重跑、零资产缺失):
|
||
rhythm gd_answer 落在首窗口前整整 1 小节(t+67.0 vs 窗口 t+69.7)、教学第 2 句
|
||
连 2 失败触发「我放慢一些」+ 慢速领奏(拍距 ×1/0.75)+ 做对恢复、菜单恢复
|
||
「四拍之后,继续」+ 4 记底鼓 count-in 在;escape 保险丝后紧接 gd_next_fuse、
|
||
其后再走两步;simon 看门狗提示上滑重听 + 期望恰为 up 时上滑作答 + 双击音
|
||
双击作答,全程无双击歧义时刻;space 每次撞击前 500ms 警报与「左!/右!/上!/
|
||
下!」同窗到达。
|
||
|
||
---
|
||
|
||
# 14 · 向导交互层设计裁定(round4 v1.3 增补)
|
||
|
||
> 依据:research/04-playtests/round3/synthesis.md(H1~H5 + §3 新语音表,唯一事实源)。
|
||
> 本文只做**追加**,上文 v1 / round2 / round3 裁定不回改;实现载体同前
|
||
> (`web/engine/guide.js` + 各游戏 game.js 接线),全部改动已落地。
|
||
|
||
## 11. round4 裁定落地摘要(H1~H5)
|
||
|
||
| # | 裁定 | 落地 |
|
||
|---|---|---|
|
||
| H1 | escape 目标带方位 | 目标句接线点盘点:**found_key**(储物间拾钥匙→cabinet (2,1))、**gd_next_fuse**(开柜得保险丝→box (0,0))、**fix_box**(修电箱通电→gate (2,2))三处,句尾接播 `gd_room_l/r/u/d`(游戏反馈层全档位,gd_next_fuse 先例)。方位按房间图对当前坐标实时计算(x 0西..2东 / y 0北..2南;方向语义 = escape 移动坐标系,up/down/left/right 滑动方向即方位);斜对角只播一句、轴序与 `_navVoices` 一致(先东西后南北);目标在同一房间不播。**引导期 g7_goal 不接**:引导本身逐句带路(g3_left/g4_down),方位句冗余,且引导链被 escape playtest 场景 A/D 的 `finishVoices(3)→PLAY` 断言冻结(断言零改动红线)。 |
|
||
| H2 | simon 占用手势预告 | `_playSequence` 序列播完 400ms 的「轮到你了」回调里按本轮序列插占用预告链:含 up→`gd_occ_up`、含 doubletap→`gd_occ_dt`、两者皆有→`gd_occ_both`(都不含则不播、直达 input);链尾接第 1 轮 your_turn → `_toInput`(`_speakGuarded`,每句 2.5s 缺失兜底)。游戏反馈层全档位,插在轮次链中(**预告先于「轮到你」**)。被占用轮次(序列含 up)input 看门狗 `say` 动态置空——只发 nudge earcon 不播重听建议句(实现从简,say 按 arm 时刻序列选择);仅 doubletap 占用不影响建议(建议只关联上滑重听键)。 |
|
||
| H3 | simon 重听账目真实 | **诊断结论:教学/演练/看门狗均无隐性扣减**(教学期不触 chances;watchdog 提示不消耗机会——guide.test 既有断言)。缺口在**初始发放**:`_beginGame()` chances=1,而教学句 gd_economy 承诺「免费机会有两次」——第二次免费要打完第 4 轮才发放(每 4 轮 +1、上限 2),P1 在第 1 轮用掉唯一一次即听到绝对化「用完了」,账面对不上。**修法=使用时如实报余量**:`_relisten()` 消耗后余 1 播 `gd_chances_left1`、余 0 播 `gd_chances_left0`(替换该路径旧「用完了」句,全档位)——「用完了」从此只在真实余量为 0 时出现。答错自动消耗(retry_use + chances_out)与余 0 再求重听的拒绝(chances_out)两处保留:前者是 t7_retry 明说过的「答错可以消耗机会重听」的机会账、后者播报时点余量确为 0;且两处被 simon playtest 断言锁定(零改动红线)。初始发放数值 1 不动(playtest「初始 1 次重听机会」断言冻结;「不动玩法数值」红线仅豁免 H3 的账目真实化,不做经济重发)。 |
|
||
| H4 | simon input 看门狗首级提前 | `GUIDE_INPUT_WATCHDOG_AT` [10000,25000]→**[5000,25000]**:仅 input 首级提前(P4「10 秒干等」),升级级 25s 与两级次数不变;该常量只用于 input 看门狗,非 input 阶段不动。 |
|
||
| H5 | rhythm 归因真话 | `_tutEvaluate` 教学首次失败归因改四档:先判**应答窗口无任何尝试**(任一 cue 在窗内无尝试——出窗的自由演奏不算尝试)→ `gd_miss_none`「这拍没接」(none 优先级最高);真出手再分 wrong/early/late(沿用 `_tutAttempts` 判据)。纠正链(retry_*)不变;正片连 2 Miss 仍 `gd_miss`(`_applyMiss` 不动)。 |
|
||
|
||
## 12. round4 新增语音资产台词表(10 句 ×2 性别 = 20 文件)
|
||
|
||
全文与 synthesis §3 逐字一致(speaker/instruct 沿用各游戏旁白 pair 常量):
|
||
|
||
| 游戏 | id | 全文 | 触发 |
|
||
|---|---|---|---|
|
||
| escape | `gd_room_l` / `gd_room_r` / `gd_room_u` / `gd_room_d` | 左面的房间。/ 右面的房间。/ 上面的房间。/ 下面的房间。 | 目标句(found_key/gd_next_fuse/fix_box)播完后接播(H1,全档位) |
|
||
| simon | `gd_occ_up` | 这一轮,向上滑是作答。 | 序列含 up(H2,全档位) |
|
||
| simon | `gd_occ_dt` | 这一轮,双击是作答。 | 序列含 doubletap(H2,全档位) |
|
||
| simon | `gd_occ_both` | 这一轮,向上滑和双击都是作答。 | 两者皆含(H2,全档位) |
|
||
| simon | `gd_chances_left1` | 免费重听还剩一次。 | 免费重听用掉后余 1(H3,全档位) |
|
||
| simon | `gd_chances_left0` | 免费重听用完了。之后重听会花一次机会,别怕,慢慢来。 | 用掉后余 0(H3,全档位) |
|
||
| rhythm | `gd_miss_none` | 这拍没接。我停下的时候,就轮到你了。 | 教学应答窗口无尝试(H5,full 档,guide.error 通道) |
|
||
|
||
资产落位与管线同前:`tools/gen_voice_dual.py --game <g> --only <id>` GPU 逐条生成 →
|
||
`--convert` 落盘 → `tools/check_all_assets.py` 终检。
|
||
|
||
## 13. round4 验证记录
|
||
|
||
- 6 playtest(guide=off)**断言零改动全绿**:storyline 54 / escape 103 / simon 108 /
|
||
rhythm 81 / space 113 / rpg 139(与 round3 基线一致)。
|
||
- `web/harness/guide.test.mjs` **120 条断言全绿**(round3 基线 93 条中仅 ② 块两条
|
||
input 看门狗时刻断言随 H4 10s→5s 更新,并固定第 1 轮序列以隔离占用预告的动态
|
||
say;其余既有断言零改动):新增 H 组 27 条——H1 方向映射按图校验(l/r/u/d +
|
||
同房间 null)+ 三处目标句接线在真实解谜链上验证;H2 三种占用预告 + 预告先于
|
||
「轮到你」+ up 占用轮看门狗无建议句 + 仅 dt 占用不影响建议;H3 余量句与真实
|
||
余量一致(2→1 播 left1、1→0 播 left0、余 0 拒绝仍 chances_out);H4 首级 5s
|
||
(升级级不变);H5 无尝试 gd_miss_none 且不再误报 late/wrong。
|
||
- `tools/check_all_assets.py` 全绿(双格式配对、无 0 字节、全可解码、双性别集合
|
||
一致);`tools/extract_voice_text.py` 已刷新 `web/harness/voice_text.json`
|
||
(447 句)。`gen_voice_dual.py --check` 新增 10 句无时长离群;rpg/tut_b0 等
|
||
4 句「缺 staging」为 R5 既有已知项,非本轮引入。
|
||
- 转写抽查(research/04-playtests/transcripts/,6 份全部重跑、零资产缺失):
|
||
simon——R1 占用预告 t+60.1 先于「轮到你了」t+62.2,5s 首级(t+69.3)与 25s
|
||
升级(t+89.3)两级均无重听建议、期望恰为 up 时上滑作答;R5/R7 建议句 5s 准时
|
||
(t+125.4 / t+179.7),两次免费重听分别跟播「免费重听还剩一次」(t+127.5)与
|
||
「免费重听用完了。之后重听会花一次机会」(t+181.8),收工态余量 0 与播报一致;
|
||
escape——
|
||
gd_next_fuse(t+64.2)后 2.2s 接「左面的房间。」(t+66.4)、fix_box(t+85.0)后
|
||
2.1s 接「右面的房间。」(t+87.1),均在目标句后 3s 内,剧本照方位句多跨四个
|
||
房间摸到大门;rhythm——教学整拍不出手归因「这拍没接。我停下的时候,就轮到你了」
|
||
(t+23.2)而非「慢了半拍」,正片首句全漏仍 gd_miss(t+71.6,正片规则不变);
|
||
storyline/space/rpg 行为零改动。
|