137 lines
11 KiB
Markdown
137 lines
11 KiB
Markdown
# 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 豁免)。
|
||
|
||
---
|
||
|
||
## 8. round3 变更记录(simon 手势映射例外)
|
||
|
||
> round3 G5(research/04-playtests/round2/synthesis.md §2)改变了 simon 的**玩法**
|
||
> 手势映射(不是向导层断言):input 阶段双击永远=作答(第 6 音色),主动重听改绑
|
||
> 上滑。按本研究「playtest 断言零改动」红线的例外流程,本节只做追加记录 §3 受影响
|
||
> 断言的替换口径;§3 既有文字不回改,其余 5 个游戏断言零改动。
|
||
|
||
- §3 关键路径 4「主动重听:input 阶段且期望输入非 doubletap 时双击 → 断言 chances
|
||
减少、inputIdx 清零、序列重播」→ 替换为:**input 阶段上滑(且期望输入非 up)=
|
||
主动重听**,断言目标不变(chances 减少、inputIdx 清零、序列重播)。
|
||
- §3 边界「双击冲突(裁定①):期望输入恰为 doubletap 时双击 = 答题(inputIdx 前进),
|
||
不触发重听」→ 保留并强化为:**input 阶段双击永远=作答**——期望非 doubletap 时
|
||
照常判错(耗机会/死亡),不再触发重听。
|
||
- §3 边界「chances=0 时双击非期望手势:不判错(round 不变、inputIdx 不变)、播
|
||
chances_out」→ 替换为:**chances=0 时上滑非期望手势**,断言目标不变。
|
||
- 新增边界断言:期望输入恰为 up 时上滑=作答(六手势全是答题输入,00 号文档 §5.3
|
||
豁免同款);非输入阶段(gameover/菜单)上滑行为不变。
|
||
- 随上述改口的测试脚手架微调(非断言变更):两处「错手势注入」的取值从
|
||
`GESTURES.find(g => g !== exp && g !== 'doubletap')` 增加排除 `up`(round3 后
|
||
up=重听键,注入 up 会触发重听而非判错,与旧版注入 doubletap 需避开是同一道理)。
|
||
- 依据:docs/design/14-guide-layer.md「round3 v1.2」§8/G5;simon playtest 断言仅
|
||
上述 3 处改口(108 条总数不变),其余断言(含教学、复活、结算、菜单、序列约束、
|
||
速度下限)零改动。
|