Files
SoundGame/docs/design/13-playtest-criteria.md
T

111 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 13 · 六游戏试玩通过标准(playtest criteria,无头测试 agent 断言检查单)
> **给测试 agent 的使用说明**:每游戏分三节——**关键路径**(从启动到通关/结算必须按序达成的事件序列,附最大手势/步数预算)、**边界断言**(必须显式验证的容错/保护行为)、**失败即不通过**。测试可用测试钩子(如直接读取 game 实例字段、快进计时器)模拟时间,但手势只能通过引擎回调注入(模拟真实判定路径)。语音缺失不应导致卡死(看门狗是各游戏的既定实现,属被测项)。
---
## 1. storyline《声命线》
**关键路径**(单结局线,≤40 次手势):
1. 启动遮罩点按 → 音频解锁 → `n00` 旁白开始(voice 层有播放记录)。
2. 沿任一抉择路径行进:每个抉择点断言 `pendingChoice/choiceArmed` 生效,左/右滑各至少使用一次。
3. 到达任一结局节点(4 结局之一)→ 结局语音链 → 结算态单击重开回 `n00`。
**边界断言**:
- 语音播放中双击 = 重听当前节点(同一 voice id 重播)。
- 下滑呼出菜单 → 返回剧情后节点不丢(mode 恢复,不重头)。
- 中途选择产生剧情标记:`n09` 右滑后 `knowTrap === true`、`n11` 左滑后 `companion === true`、`n18` 左滑后 `betrayed === true`(标记设置即断言;knowTrap 无下游消费是已知项,roadmap §2.2,不作为失败项)。
- 语音链看门狗:屏蔽某一 voice 资产时流程仍可推进到结局。
## 2. escape《暗室》
**关键路径**(引导 8 步 + 解谜链,≤80 次手势):
1. 启动 → GUIDE 进入(g0_intro 播放)→ 依次:单击(G0)→ 任意滑动(G1)→ 滑动 ×2(G2)→ 左滑(G3)→ 下滑(G4)→ 单击拾钥匙(G5,断言 `hasKey === true`)→ 双击(G6)→ 进入 PLAY(断言 `phase === 'PLAY'`,localStorage `soundgame.escape.guideDone === '1'`)。
2. PLAY 路径:(0,2)出发 → 右滑×2 到铁柜房 (2,1) → 双击开柜(`cabinetOpen === true && hasFuse === true`)→ 左滑×2+上滑到电箱房 (0,0) → 双修复电箱(`powerOn === true`)→ 右滑×2+下滑×2 到大门 (2,2) → 双击逃脱。
3. ENDING:断言 time_band 语音播出 + 单击重开回 PLAY。
**边界断言**:
- 引导期错手势:G3 右滑 → 播 guide_wrong_left;连错 3 次 → guide_blunt_left + warning 震动(监听 vibrate 调用)。
- 撞墙:PLAY 中 (0,0) 左滑 → wall 音效 + error 震动 + 位置不变。
- 卡关提示:计时器快进 60s/120s/180s → 依次播 stuck_*_1 / stuck_*_2 / stuck_*_3 + nav_*;任意进展事件后重置(`_stuckShown` 清空)。
- 单击检查 = 环境音先播、描述 800ms 后播(断言播放顺序)。
- 双击无目标兜底:播背包 + L2 明示,不崩。
## 3. simon《音序回响》
**关键路径**(教学 + 5 轮 + 复活耗尽,≤120 次手势):
1. 启动 → 0.5s 后教学 T0(t0_welcome 播放)→ T1-T6 每步:听到 tone → 做出对应手势(断言 `teachIdx` 递进)→ T7 → 进入第 1 轮。
2. 第 1-3 轮:playback 阶段手势被忽略(注入手势断言 sequence 不受影响)→ input 阶段按 `game.sequence` 原样复现 → `round` 递增。
3. 触发复活:第 4 轮故意答错 → 断言 `chances` 1→0、序列**不变**重播(`sequence` 引用值相等)→ 复现成功 → 第 4 轮完成时 chances 回 1(每 4 轮 +1)。
4. 主动重听:input 阶段且期望输入非 doubletap 时双击 → 断言 chances 减少、inputIdx 清零、序列重播。
5. 耗尽后再答错 → gameover → 断言 score_band 语音与 `round-1` 匹配 → 单击重开跳过教学直达第 1 轮。
**边界断言**:
- 无 BGM:全程无 bgm 层播放调用。
- 双击冲突(裁定①):期望输入恰为 doubletap 时双击 = 答题(inputIdx 前进),不触发重听。
- chances=0 时双击非期望手势:不判错(round 不变、inputIdx 不变)、播 chances_out。
- 序列约束:前 5 轮无三连同手势;全程无四连。
- 速度:第 1 轮 interval 700ms、第 12 轮起 420ms 下限。
## 4. rhythm《节拍行者》
**关键路径**(教学 + 曲目一通关 + 解锁,≤200 次手势):
1. 启动 → welcome → 教学 T1-T3:按 cues 的 expected 时刻(测试用 AudioContext 时钟对齐)做对应手势 → `tutorialDone === true` → 进曲目一 main。
2. 曲目一:按 `_cues` 全部应答(Perfect 精度注入)→ 结算 phase 'end' → 断言评级 S(全 Perfect)→ `grades.song1 === 's'`、`unlocked === 2`、unlock_song2 播报。
3. 结算单击 = 同曲再来一遍;右滑 = 下一首(已解锁 song2 进入 main)。
**边界断言**:
- tap 补偿:tap 音符以"回调时刻 -0.30s"判定(注入 tap 手势的实际回调延迟下仍判 Perfect)。
- Miss=无乐器音:窗口内做错手势 → 无 inst_* 播放 + error 震动 + combo 清零。
- 下滑折中:main 中无临近 down 音符时下滑 → 菜单(phase 'menu'、BGM 断点);有临近 down 应答音符时下滑 = 演奏判定,不开菜单。
- 菜单暂停恢复:关菜单后 cue.expected 平移、BGM 断点续播(断言 `_bgmT0` 平移量 = 暂停时长)。
- 教学失败 2 次 → retry_skip 跳过该步不卡死。
- **结算末位**:song3 结算页右滑 → 不播 song_locked(round3-4 裁定①的回归断言;修正落地前此断言预期失败,标记 known-issue)。
## 5. space《盲航》
**关键路径**(演练 + 保护期 + 坠毁,≤150 次手势):
1. 启动 → 演练 D1-D4:按 `DRILLS[d].dir` 同向滑 → `drillIdx` 递进 → D5 后进 playing(`drillDone === '1'`)。
2. 保护期(runStart 起 60s):等一颗陨石 → **不滑动任其撞** → 断言 `hits === 0`(训练护盾吸收)+ protect_<dir> 播报。
3. 第 20s:feature 阶段单击 → boost 生效(`boostUntil > now`);第 45s:双击 → 护盾(`shieldUpUntil > now`)。
4. 60s 后:保护解除播报;之后正常闪避 3 颗(同向滑,断言 dodges=3)→ 再任撞 3 次 → 坠毁 gameover。
5. 结算:time_/dodge_ 分档句与实际值匹配 → 单击重开。
**边界断言**:
- 演练做错:D1 右滑(应为左)→ drill_retry_left 重教 + 同一步重试;失败 2 次 → drill_moveon 带过。
- 保护期撞击方位归因:撞左来陨石播 protect_left(方向句与 ob.dir 一致)。
- 同向判定:撞击前 1.5s 内同向滑 = dodge(dodges+1);反向滑 ≠ dodge。
- 第 2 次被撞后追加 hit_last;hits===3 才 gameover。
- 下滑折中:下方有悬置陨石时下滑 = 闪避;无下方陨石时下滑 = 菜单(phase 'menu')。
- 护盾充能:doubletap 后 30s 内 shieldReadyAt 锁定,到时播 shield_ready。
- 里程碑:dodges=10 播 ms_10(测试可快进或直接设置 dodges 后触发一次 dodge)。
## 6. rpg《剑与声》(含 11 号文档重构项;重构未落地处标 known-issue)
**关键路径**(第一章通关,≤300 次手势):
1. 启动 → 无存档时序章 intro_1-3 → village;断言场景进入 = amb/desc 播报 + 选项可左右滑切换。
2. village:商店买铁剑(金币 50→断言不够 → 先调查/战斗攒钱或直接断言 shop_poor 播报路径);上滑状态播报链完整(st_lv→st_hp→st_gold→st_weapon→st_armor)。
3. path:investigate 一次性 +15 金(再次调查播 evt_nothing)。
4. stream:**教学战不败**——全程乱按/不动,断言玩家 HP 不低于 1(锁底);按 11 号文档重构后:四步教学(menu→attack→parry→defend)依次断言 teachStage 流转(重构落地前按现版两步 parry→attack 断言)。
5. hunter:talk_hunter → hunter_quest flag + potions+1 + shop_discount。
6. deepwood:山贼连战(两只依次上场,连战间不回血)→ enc_bandits_done。
7. gate:assault → elite 战 → boss1:黑风寨主(半血二阶段 ATK 12 + npc_boss1_2)→ 胜利 → evt_ch1_end → `chapters['2'] === 'open'`。
8. 存档断言:任一战斗结算后 PUT/localStorage 有最新 data(summary 含场景名与 Lv);杀进程重进 → sys_continue_ask → 单击继续落点正确。
**边界断言**:
- 格挡:前摇窗口内双击 → 伤害 ×0.3(`dmg` 断言或 HP 差值断言);窗口外双击 → error 震动不生效。
- 防御指令:当回合伤害 ×0.5。
- 逃跑:Lv<3 普通战 100% 成功(11 号文档;重构前现版为 flee 布尔,按现版断言 flee:true 必成);Boss 战下滑 → btl_noflee。
- 新手保护(11 号文档,known-issue 至重构落地):前 3 场前摇 1.5s、伤害 ×0.6;enc_boss1 恒标准档。
- 战败:HP≤0 → btl_lose → village 重生,等级/金币/flags 保留、非 Boss 遭遇重置。
- 菜单豁免:探索态下滑=菜单(左右滑+单击确认),战斗态下滑=逃跑。
- 看门狗:屏蔽任意 voice 资产,战斗与场景流转不卡死。
## 7. 全局通用断言(每游戏都跑)
1. 启动遮罩点按前无音频播放(引擎解锁语义)。
2. 全程无未捕获异常;资产缺失仅 console.error 不崩。
3. 设置边界:settings.voice 切换后下一句起用对应目录(voice 缓存键含性别);settings.bgm=0 时无 bgm 层加载;speed=1.7 时下一句 playbackRate 生效。
4. 双击=重听在其声明可用的阶段生效(escape 检查/simon 规则/rpg 场景 desc 等)。
5. 菜单约定(裁决②):适用游戏的模态菜单 = 单击循环 / 双击确认 / 上滑帮助 / 下滑关闭(RPG 豁免)。