round3: G1 gd_answer提前一小节(根因=排程压窗起点) + G2教学降难DDA + G3 count-in修复(根因=未重排调度队列) + G4 escape目标链 + G5 simon双击根治(重听改上滑,重录3句) + G6轮成功/破纪录 + G7 space方向呼喊 + 22语音文件 + guide93断言全绿

This commit is contained in:
SoundGame Dev
2026-08-31 01:40:51 +08:00
parent ec89629eb4
commit 9f8096377e
537 changed files with 1046 additions and 432 deletions
+30 -9
View File
@@ -19,10 +19,12 @@
* - 反馈全部改震动:对/错 SUCCESS/ERROR,sfx/correct、wrong、newrecord 已删除;
* sfx/gameover 保留为内容性结束音。
*
* 设计冲突的处理(02 文档 §4.2 与 §6.3):双击既是六种音色之一(序列可出现
* doubletap)又是"主动重听"手势。本实现按**上下文**判定:输入阶段若当前期望
* 输入恰为 doubletap,双击视为答题;否则视为重听(有机会时)。两者不会同时
* 歧义落空——序列永远可答,重听仅在"不期望双击"时可用。
* 设计冲突的处理(round3 synthesis G5 裁定,替代 round2 的双击语境判定):双击是
* 六种音色之一(序列可出现 doubletap),历史上又兼「主动重听」。round3 改全局规则:
* **input 阶段双击永远=作答(第 6 音色)**——期望恰为 doubletap 判对,否则照常判错,
* 不再承担重听;主动重听改绑**上滑**(期望输入恰为 up 时上滑=作答,六手势全是
* 答题输入的 00 §5.3 豁免同款)。非输入阶段行为不变(gameover/菜单上滑仍是规则/
* 帮助)。同一手势在 input 阶段不再有第二种含义(P1 round2 P0 根治)。
*
* 手势 → 音色映射:
* up 上行琶音 / down 下行低音 / left 左声道弹拨 / right 右声道弹拨 /
@@ -87,6 +89,9 @@ export class SimonGame extends Game {
this._menuIdx = 0;
this._session = 0; // 会话令牌:重开后使旧计时器/语音链回调失效
this._timers = [];
// G6(round3):轮结算链尾轻量反馈每局各限 1 次
this._clearSaid = false;
this._recordSaid = false;
}
start() {
@@ -205,8 +210,9 @@ export class SimonGame extends Game {
if (this.teachIdx + 1 < GESTURES.length) {
this._teachStep(this.teachIdx + 1);
} else {
// T7:收尾两句 + 机会经济一句(round2 F5:记不住就双击重听、免费两次、
// 用完扣机会——P1「经济不透明」开局一句话讲清)→ 正式对局
// T7:收尾两句 + 机会经济一句(round2 F5 → round3 G5 重录:记不住就
// 向上滑重新听、免费两次、用完扣机会——P1「经济不透明」开局一句话
// 讲清,且与新手势映射一致)→ 正式对局
this._speakGuarded(['voice/t7_ready', 'voice/t7_retry', 'voice/gd_economy'],
() => this._beginGame(), 20000);
}
@@ -234,6 +240,8 @@ export class SimonGame extends Game {
this.sequence = [];
this.round = 0;
this.chances = 1;
this._clearSaid = false; // G6:每局重新封顶
this._recordSaid = false;
this._nextRound();
}
@@ -346,9 +354,10 @@ export class SimonGame extends Game {
}
_onInput(g) {
// 双击的上下文判定(见文件头"设计冲突的处理"):
// 期望输入是 doubletap → 答题;否则 → 主动重听(耗机会)
if (g === 'doubletap' && this.sequence[this.inputIdx] !== 'doubletap') {
// G5(round3):双击永远=作答(第 6 音色)——期望恰为 doubletap 判对,否则
// 照常判错,不再承担重听。主动重听改绑上滑:期望输入恰为 up 时上滑=作答
// (六手势全是答题输入,00 §5.3 豁免同款),其余时刻上滑=主动重听(耗机会)。
if (g === 'up' && this.sequence[this.inputIdx] !== 'up') {
this._relisten();
return;
}
@@ -390,6 +399,18 @@ export class SimonGame extends Game {
vibrate('pickup');
ids.push('voice/chance_plus');
}
// G6(round3):轮结算链尾轻量反馈——gd_clear「漂亮,过了。」每局 1 次;
// 本轮完成数超过历史最佳(且确有旧纪录可破)时追加 gd_record「破纪录了。」
// 每局 1 次(结算另有 new_record,此处是局中破纪录的即时一刻)。游戏规则句
// 随链播(全档位,gd_economy 先例),不走向导通道。
if (!this._clearSaid) {
this._clearSaid = true;
ids.push('voice/gd_clear');
}
if (!this._recordSaid && this.best > 0 && this.round > this.best) {
this._recordSaid = true;
ids.push('voice/gd_record');
}
this._speakGuarded(ids, () => {
if (s !== this._session) return;
this._timer(() => this._nextRound(), 300);