save
This commit is contained in:
+154
-167
@@ -1,227 +1,214 @@
|
||||
# 00 · 全局交互规范(Global UX)
|
||||
|
||||
> **给开发者的实现要点摘要**
|
||||
> 1. 设置项(voice / speed / bgm / guide / input)只在大厅页用 `<select>` 可视化 UI 修改,存 `localStorage["soundgame.settings"]`,由 `engine/settings.js` 管理;游戏启动时只读生效,游戏内不提供修改入口(菜单里只播报当前值)。**R1 已落地,本文 §1/§2/§4 已按实现修订(R2 修订版);R7 增补 guide 设置与向导层(§6,见 14 号文档);P0-A 增补 input 设置(§1.1,见 §5.5)。**
|
||||
> 2. 所有提示音反馈改为震动:`engine/haptics.js`(**已实现**,震型名小写:`confirm/error/success/warning/swipe/heartbeat`);iOS Safari 不支持时**静默降级,绝不回退到提示音**。
|
||||
> 3. 旁白全部整句预生成:禁止数字/碎片拼接(音色漂移根因),每款游戏旁白固定同一 `speaker` + 同一 `instruct` 常量。
|
||||
> 4. 手势全局约定:上滑=帮助/状态、下滑=菜单、单击=确认/继续、双击=重听、左右滑=选择/移动;以滑动为核心玩法的游戏可偏离(见 §5 豁免表),但必须在开场交互教学中讲清。**PC 键盘平行通道(§5.5,P0-A 已实现)不改变这些语义——同一手势宪法、同一状态机,仅多一条输入通路。**
|
||||
> 5. 用户系统:大厅页登录,进度经 `web/server/server.js` REST API 存服务器(**已实现**),本地 localStorage 做离线缓存。
|
||||
> 1. **交互权威**是 [26-audio-interaction-playbook.md](26-audio-interaction-playbook.md)。本文是它在本项目的施工口径。两份冲突时以 26 号为准。`research/02-methodology` 与旧豁免表一律让路。
|
||||
> 2. 设置项(voice / speed / bgm / guide / input)只在大厅页改,存 `localStorage["soundgame.settings"]`,游戏内只读。
|
||||
> 3. **每次操作必须有声音回执**(ok / invalid / busy,§2)。震动是补充,不是主通道。电脑和 iPhone 没有震动时,回执声仍要响。
|
||||
> 4. 旁白整句预生成,禁止数字/碎片拼接。指令句 ≤12 字;叙事句 ≤25 字。
|
||||
> 5. **新手期只开放三个手势**:单击、左右滑、上滑。双击默认不存在。四向滑动是核心玩法时,帮助统一换到长按(全项目同一条,不许各游戏各换)。
|
||||
> 6. 用户系统:大厅登录,进度走 REST API,本地 localStorage 离线缓存。
|
||||
|
||||
---
|
||||
|
||||
## 0. 文档地位与废止清单
|
||||
|
||||
本文取代自己 R1~R7 的手势宪法、向导接线、以及「操作反馈一律只靠震动」的旧裁定。下列旧规则**废止**:
|
||||
|
||||
| 废止 | 改为 |
|
||||
|---|---|
|
||||
| 双击 = 重听(全局默认) | 新手期不识别双击;阶段 3 以后才解锁,且不得绑重播整段、重开 |
|
||||
| 单击等 300ms 双击窗 | 新手期 `doubleTapWindow: 0`,松手即单击 |
|
||||
| 无效操作只震不说 | 声音回执 `invalid` + 每个「状态×手势」解释一次 |
|
||||
| iOS 无震动则无反馈 | 回执声永远出声;震动可有可无 |
|
||||
| 各游戏豁免表各换帮助入口 | 四向滑动是玩法 → 帮助一律长按 |
|
||||
| 菜单:单击循环、双击确认 | 菜单:左右滑切换、单击确认(与探索同构) |
|
||||
| 看门狗原样重播说明书 | 三档提示:完整句 → 短句 → 提示音 |
|
||||
| 向导语音 `queue:true` 永不打断 | 玩家一动游戏就停(关键句除外,≤3s) |
|
||||
| 句间恢复 BGM duck | 整条语音链期间保持压低 |
|
||||
|
||||
仍有效、未改:设置系统、旁白整句管线、用户进度 API、键盘平行通道的键位表(语义随新手模式变)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 设置系统(已实现:engine/settings.js + 大厅设置面板)
|
||||
|
||||
### 1.1 四个设置项的精确语义
|
||||
### 1.1 设置项语义
|
||||
|
||||
| 设置项 | 取值(实现值) | 精确语义 |
|
||||
| 设置项 | 取值 | 精确语义 |
|
||||
|---|---|---|
|
||||
| `voice` | `"female"`(默认)/ `"male"` | 切换 **voice 资产目录**。`play('voice/xxx')` 实际解析为 `audio/voice/<gender>/xxx.{ogg,m4a,mp3,wav}`,找不到时**回退平铺的 `audio/voice/xxx.*`**(已实现;storyline 角色台词靠此回退)。两性别的 id 集合由资产侧保证完全一致(见 docs/audio/round1-report.md),因此不做"回退另一性别"的逻辑。 |
|
||||
| `speed` | `1.0`(默认)/ `1.35` / `1.7` / `2.2` | **只作用于 voice 层**的 `playbackRate`(创建 voice source 时实时读取,**从下一句开始生效**,正在播的句子不变速)。BGM、sfx 速率不变。TTS 一律按 1.0 语速生成;`instruct` 里禁止出现语速描述词。**2.2 档为视障档**(R7 增补:资深读屏用户听速 250+ WPM,见 research/01-literature/03)。 |
|
||||
| `bgm` | `1.0`(默认)/ `0.3` / `0` | BGM 层独立增益总线系数。`0` = 不加载、不播放任何 `bgm/` 资产(`_playBgm` 短路),ducking 逻辑保持原样。改设置即时生效(已实现 subscribe 机制)。 |
|
||||
| `guide` | `"full"`(默认)/ `"standard"` / `"off"` | **向导帮助等级**(R7 增补,engine/guide.js 实时读取,见 §6 与 14 号文档):`full`=签名 earcon+向导语音+震动(新手全托管);`standard`=只留 earcon+震动(无向导语音,尊重专家);`off`=全静且**不挂任何看门狗定时器**(老手/回归测试)。 |
|
||||
| `input` | `"auto"`(默认)/ `"touch"` / `"key"` | **提示文案输入模式**(P0-A 增补,`gesture.inputMode()` 读取):`auto`=跟随最近使用的通道(键盘 keydown→key,任意 touchstart→touch,会话内无输入时按能力检测);`touch`/`key`=手动覆盖。**只影响提示文案**(如启动遮罩「轻触开始」/「按空格开始」),**不关闭任何输入通道**——三通道永远并行(混合设备)。 |
|
||||
| `voice` | `"female"`(默认)/ `"male"` | 切换 voice 资产目录。`play('voice/xxx')` 解析为 `audio/voice/<gender>/xxx.{ogg,m4a,mp3,wav}`,找不到回退平铺 `audio/voice/xxx.*`。两性别 id 集合必须一致。角色/NPC 音走平铺,不切性别。 |
|
||||
| `speed` | `1.0` / `1.35` / `1.7` / `2.2` | 只作用于 voice 层 playbackRate,从下一句生效。TTS 按 1.0 生成。`2.2` 为视障档。 |
|
||||
| `bgm` | `1.0` / `0.3` / `0` | BGM 层增益。`0` = 不加载不播放任何 `bgm/`。内容环境音在 sfx 层,不受此项误杀。 |
|
||||
| `guide` | `"full"`(默认)/ `"standard"` / `"off"` | 向导等级:`full`=等待声+三档提示语音+回执;`standard`=等待声+回执+提示音,无向导语音;`off`=回执仍在,不挂迷茫/看门狗定时器。 |
|
||||
| `input` | `"auto"` / `"touch"` / `"key"` | 只影响提示文案,不关闭任何输入通道。三通道永远并行。 |
|
||||
|
||||
存储:localStorage key = `soundgame.settings`,值形如:
|
||||
存储 key = `soundgame.settings`。非法键/值逐项丢弃。`speed`/`bgm` 存数值。
|
||||
|
||||
```json
|
||||
{ "voice": "female", "speed": 1.0, "bgm": 1.0, "guide": "full" }
|
||||
```
|
||||
### 1.2 修改入口
|
||||
|
||||
注意(与设计初稿的差异,**以实现为准**):`speed`/`bgm` 存**数值**(1.0/1.35/1.7、1.0/0.3/0),不是字符串枚举;`engine/settings.js` 对非法键/值逐项丢弃,永不炸。
|
||||
只在大厅。游戏内菜单可播报当前值,并说「请回到大厅修改」。大厅变更后应播一句样例(voice+speed),未做则补,非阻塞。
|
||||
|
||||
### 1.2 修改入口:只在大厅页(已实现)
|
||||
### 1.3 服务器同步
|
||||
|
||||
- `web/index.html` 大厅已有"设置"面板:四个 `<select>`(旁白音色:女声/男声;语速:正常/快/特快/特快++;背景音乐:正常/小/关闭;向导帮助:详细/只听提示音/关闭),变更即 `settings.set()` 写 localStorage。
|
||||
- 试听句(设计有、R1 未做):变更后播一句样例语音演示 voice+speed,列为 R3 打磨项,非阻塞。
|
||||
- 游戏内:**只读**。`audio.js` 自动应用三项设置,游戏代码无需改动;下滑呼出的菜单里用语音播报当前设置(如"当前:女声,正常语速"),并提示"请回到大厅修改设置"。
|
||||
设置作为特殊游戏键 `_settings` 走进度接口。登录后服务器覆盖本地。离线纯 localStorage。
|
||||
|
||||
### 1.3 服务器同步(已实现,形式与初稿不同)
|
||||
---
|
||||
|
||||
- 实现:**没有独立的 `/api/settings`**。设置作为特殊游戏键 `_settings` 存进进度接口:大厅在变更时 `PUT /api/progress { game: '_settings', data: settings.get() }`;登录后 `GET /api/progress?game=_settings` 拉回覆盖本地(服务器为准)。
|
||||
- 离线/未登录:纯 localStorage,行为不变。
|
||||
## 2. 输入回执与震动
|
||||
|
||||
## 2. 震动语言规范(已实现:engine/haptics.js)
|
||||
### 2.1 回执是主通道(26 号原则 4)
|
||||
|
||||
### 2.1 动机
|
||||
三种合成系统音,全项目统一,接引擎 master,不走 sfx 内容资产:
|
||||
|
||||
用户反馈⑦:提示音(确认音、错误音)与游戏音效/线索音混在一起,盲玩时无法区分"这是反馈还是游戏内容"。震动是独占的触觉通道,不会与任何音频信息混淆。所有"操作反馈"一律用震动;音频只承载游戏内容与叙事。
|
||||
|
||||
### 2.2 引擎模块(以实现为准)
|
||||
|
||||
`web/engine/haptics.js`(R1 已落地):
|
||||
|
||||
```js
|
||||
import { vibrate, hapticsSupported, HAPTIC_PATTERNS } from '../engine/haptics.js';
|
||||
vibrate('error'); // 预定义名称(小写)
|
||||
vibrate([15, 40, 15]); // 自定义震型数组
|
||||
```
|
||||
|
||||
已实现预定义震型(R2 已补全,**以此 10 种为准**):
|
||||
|
||||
| 名称 | 震型 (ms) | 语义用途 |
|
||||
| 回执 | 何时 | 听感(起步参数) |
|
||||
|---|---|---|
|
||||
| `confirm` | [20] | 确认:点按确认、菜单选中 |
|
||||
| `error` | [60, 40, 60] | 错误:两连震(做错手势、无效操作) |
|
||||
| `success` | [100] | 成功:长震(过关、解谜成功、升级) |
|
||||
| `warning` | [30, 50, 30, 50, 30] | 警告:三连短震(血量低、卡关提示) |
|
||||
| `swipe` | [10] | 滑动识别成功(最轻,引擎内置) |
|
||||
| `heartbeat` | [40, 100, 40] | 心跳/倒计时紧张感 |
|
||||
| `pickup` | [15] | 获得物品/机会(单轻震,不与 error 混淆) |
|
||||
| `hit` | [80] | 受击/终结性失败:单次重震 |
|
||||
| `beat` | [8] | 节拍锚点(simon/rhythm 领奏专用,极轻) |
|
||||
| `danger` | [25, 40, 25, 40, 25] | 危险逼近(可循环,每遍间隔 ≥400ms;RPG 无声前摇用它代替听觉提示) |
|
||||
| `ok` | 操作被接受并生效 | 三角波 1600Hz,35ms,增益 0.08,「嗒」 |
|
||||
| `invalid` | 收到了,但现在用不上 | 正弦 260→200Hz,120ms,增益 0.10,低沉「咚」 |
|
||||
| `busy` | 游戏在说关键句或正在处理 | 正弦 520Hz,40ms,增益 0.04,很轻「嗯」 |
|
||||
|
||||
### 2.3 语义绑定规则(含引擎内置反馈的分工)
|
||||
规则:
|
||||
- 100ms 内出声;回执 ≤0.2s。
|
||||
- 游戏已为这次操作播了明显内容音(脚步、开门),可省 `ok`(记 `silent-ok`)。`invalid` 与 `busy` 永远播。
|
||||
- 系统音一律合成;内容音一律录音。两类永不混用。
|
||||
- 单击执行「继续/跳过」后 **400ms 内**再来的单击只给 `busy`,不连跳、不误进下一段。
|
||||
|
||||
- **gesture.js 已内置基础反馈**(R1 实现):滑动识别成功→自动 `swipe`;tap/doubletap→自动 `confirm`。因此**游戏层不要再对"手势被识别"本身调 `confirm`/`swipe`,否则双重震动**。游戏层只在语义事件处调用:`error`(操作被判定为错)、`success`(过关/成就)、`warning`(警告)、以及自定义 PICKUP/HIT/BEAT/DANGER。
|
||||
- 震型按**语义**选用,不按游戏选用:任何游戏的"操作错误"都是 `error`,玩家在不同游戏间迁移时触觉语言一致。
|
||||
- 单次震动总时长 ≤ 500ms;DANGER 循环时每遍间隔 ≥ 400ms,事件结束立即 `navigator.vibrate(0)` 停止。
|
||||
- 震动的触发源只有两类:a) 玩家的手势被系统接收/拒绝(引擎内置或游戏层语义判定);b) 明确的离散游戏事件(受击、警告、节拍点)。**禁止**持续型/背景型震动。
|
||||
### 2.2 震动是补充(已实现:engine/haptics.js)
|
||||
|
||||
### 2.4 绝不用震动的场景
|
||||
十种震型名不变:`confirm/error/success/warning/swipe/heartbeat/pickup/hit/beat/danger`。语义仍按语义选用,不按游戏选用。
|
||||
|
||||
1. **长对白播放中**(voice 层有音频在播):旁白叙事期间不震动,避免震动机理掩盖语音细节、也让玩家误以为需要操作。例外:教学流程里"现在请向左滑"这类等待玩家操作的指令句,在语音**播完后**允许一次轻震提示可以操作——震动发生在 voice 结束后,不重叠。注意:教学里玩家出手后引擎已自动震 swipe/confirm,游戏层通常无需再补。
|
||||
2. 序列/乐句播放中需要玩家纯聆听记音高的阶段(simon/节奏游戏领奏时例外:BEAT 本身就是节拍信息通道,见 02/03 文档)。
|
||||
3. 同一 200ms 窗口内多个事件只震一次(实现上去抖)。
|
||||
4. 开场遮罩、大厅页等可视化 UI 不震动。
|
||||
- gesture.js 内置:滑动→`swipe`,tap/doubletap→`confirm`。游戏层不要对「手势被识别」再震一次。
|
||||
- 单次 ≤500ms;danger 循环间隔 ≥400ms;200ms 窗口去抖。
|
||||
- 长对白、纯聆听记音阶段不震(节拍锚点 `beat` 除外)。
|
||||
- iOS 无震动:no-op。**不再把「绝不回退提示音」理解成「无任何声音反馈」**——回执声仍然要响。旧教学口径「iPhone 用户听结果声」改为「听回执声和结果声」。
|
||||
|
||||
### 2.5 iOS Safari 降级策略
|
||||
---
|
||||
|
||||
iOS Safari 不支持 `navigator.vibrate()`。策略:**静默降级**——`haptics.js` 特性检测 `'vibrate' in navigator`,不支持即 no-op(已实现)。**不允许**回退到提示音(反馈⑦的根因就是提示音混淆;iOS 用户没有反馈音,好过错乱的反馈音)。iOS 玩家依赖已有的音频结果反馈(脚步、撞击、机关声),这些属于游戏内容音,保留。各游戏开场教学统一口径:"做对做错,手机会震动告诉你;iPhone 用户听结果声"。
|
||||
## 3. 旁白质量与台词写作
|
||||
|
||||
## 3. 旁白质量规范
|
||||
整句生成、分段数字、同游戏同 speaker+instruct、管线 `tools/gen_voice_dual.py`、双格式 ogg+m4a:沿用原规范。
|
||||
|
||||
### 3.1 根因
|
||||
**26 号增补(写作强制)**:
|
||||
|
||||
用户反馈⑥的"音色漂移、发音不准"来自两类做法(旧版 escape/simon/space):
|
||||
| 用途 | 规则 | 例子 |
|
||||
|---|---|---|
|
||||
| 指令 | 「动作 + 结果」,≤12 字 | 「向左滑,开门。」 |
|
||||
| 短句档 | ≤6 字,只留动作 | 「向左滑。」 |
|
||||
| 叙事 | 单句 ≤25 字 | |
|
||||
| 我在哪 | 位置。目标。一个动作。≤20 字 | 「厨房。找钥匙。左右滑。」 |
|
||||
| 归因 | 原因 + 下次怎么做;必须真实 | 「慢了。听到就滑。」 |
|
||||
| 肯定 | ≤4 字 | 「对。」 |
|
||||
| 解释无效 | 现在怎样。能做什么。每个状态×手势一次 | 「还在讲故事。点一下可以跳过。」 |
|
||||
|
||||
1. **碎片拼接**:`voice/di` + `voice/num_5` + `voice/lun` 拼"第 5 轮"。每个碎片独立生成,音色、气息、响度逐片漂移,接缝明显。
|
||||
2. **同游戏多 instruct / 长短不一**:有的句带情感指令有的不带,批次间模型状态不一致。
|
||||
每句台词标类别:`critical` / `content` / `hint` / `feedback`(26 §4.6)。`critical` ≤3s。`hint`/`feedback` 空闲才播,过期丢弃。
|
||||
|
||||
### 3.2 规范(所有游戏强制执行)
|
||||
禁止:「如果」「可以尝试」;一句里教两个手势;游戏主动原样重复。
|
||||
|
||||
1. **一句一文件,整句生成**。凡要播报给玩家的信息,整句一次 TTS 生成,禁止运行时拼接。例外:>40 字的长台词由资产管线在生成期拆句拼接(R1 管线已支持,见 docs/audio/round1-report.md),运行时仍不拼。
|
||||
2. **数字信息改分段整句**。需要报数字的场景(轮数、成绩、存活时间、用时、准确率),按取值分段预生成整句:
|
||||
- 取值少且可数(如 simon 轮数):直接为每个值生成整句,"第一轮"…"第二十轮",超出范围用无数字兜底句。
|
||||
- 取值连续(如存活秒数、准确率):按区间分段整句,如"不到三十秒""超过一分钟""准确率超过八成五"。宁粗勿拼。
|
||||
- 各游戏的具体分段在各自设计文档中给出。
|
||||
3. **同游戏同音色**:每款游戏的旁白用固定 speaker 常量 + 固定 INSTRUCT 常量。R1 音色分配表(docs/audio/round1-report.md §4,**以此为准**):male 一律 Uncle_Fu;female:storyline=Vivian、escape=Serena、simon=Serena、rhythm=Vivian、space=Serena。角色音(storyline/RPG 的 NPC)可另有角色 speaker,但**同一角色**所有句子的 speaker+instruct 必须是同一常量,写死在 gen 脚本的台词表表头注释里;NPC 台词不做双性别,平铺存 `voice/` 根目录(引擎平铺回退会命中)。
|
||||
4. **短句优先**:单句 ≤ 25 个汉字为宜;长信息拆成多句链播(onComplete 串行),每句仍是完整句,不是碎片。
|
||||
5. **生成管线**:统一用 `tools/gen_voice_dual.py`(R1 已建,台词表驱动,female/male 双跑、断点续跑、ogg+m4a 双格式、峰值归一 0.89)。新台词表由策划以"voice-ids 文档"形式交付(id + 全文 + speaker + instruct),音频总监照录进该脚本。
|
||||
6. **验收**:自动 QC(时长/峰值/两性时长离群)+ 人工试听;多音字风险句在台词表中标注替代写法(如"重听"→"重新听")。
|
||||
---
|
||||
|
||||
## 4. 用户系统(服务器进度,已实现:web/server/server.js)
|
||||
## 4. 用户系统(已实现)
|
||||
|
||||
### 4.1 形态(已实现)
|
||||
形态、API、`summary` 必填、`_settings` 保留键:不变。
|
||||
|
||||
- 大厅页"用户"面板:用户名 + 4-6 位数字 PIN 注册/登录;token 存 localStorage key `soundgame.auth`(形如 `{ username, token }`),请求头 `Authorization: Bearer <token>`。
|
||||
- 服务端 `web/server/server.js`(Node 零依赖,静态托管 + API 一体,`serve.sh` 拉起);数据落盘 `web/server/data/`。局域网玩具级认证,勿暴露公网。
|
||||
- 未登录/服务器不可达:静默降级为仅本地模式,进度只存 localStorage(key `soundgame.progress.<game>`)。
|
||||
**26 号增补**:退出自动存;重进 5 秒内播一句局面复述(位置 + 目标 + 现在做什么),然后交出话轮。复述句 id 随等待点写入进度。
|
||||
|
||||
### 4.2 API 约定(以实现为准)
|
||||
---
|
||||
|
||||
```
|
||||
POST /api/register { username, pin } -> 201 { ok, username }
|
||||
POST /api/login { username, pin } -> 200 { ok, token, username }
|
||||
GET /api/progress?game=<game> (Bearer) -> 200 { game, data } (无存档则 data=null)
|
||||
PUT /api/progress { game, data } (Bearer) -> 200 { ok, game }
|
||||
```
|
||||
## 5. 手势宪法(26 号原则 6)
|
||||
|
||||
与初稿的差异(**以实现为准**):进度读写用 `?game=` 查询参数 / 请求体字段,不是路径段;`data` 是各游戏**自由格式**的 JSON(服务器不校验结构);没有统一的 `{schema, game, updatedAt, data}` 信封——游戏自行在 `data` 内放 `schema`/`updatedAt` 字段(建议保留,便于迁移)。
|
||||
### 5.1 新手期三手势(全部游戏共用)
|
||||
|
||||
### 4.3 进度 data 的两条约定
|
||||
| 手势 | 唯一含义 | 游戏在说时 | 等你操作时 |
|
||||
|---|---|---|---|
|
||||
| 单击 | 继续 / 确定 / 听一下 | 只跳过当前这句(`skipVoice`),给 `ok` | 执行继续或确定 |
|
||||
| 左滑 / 右滑 | 选择 / 移动 | 打断并执行 | 执行 |
|
||||
| 上滑 | 我在哪、我该干嘛(一句) | 打断后回答 | 回答 |
|
||||
|
||||
1. **`summary` 字符串(必须)**:大厅游戏卡片会直接显示 `data.summary`(已实现,index.html `loadProgress()`)。每个游戏的存档 data 里必须维护一句人话摘要,如 `"第一章·溪流 · Lv3 · 金币120"`、`"最高纪录:12 轮"`。
|
||||
2. 保留键 `_settings`(设置同步用,见 §1.3),游戏不得占用。
|
||||
3. 写进度时机:局内关键节点(过关、死亡结算、退出菜单选"保存并回大厅")自动 PUT + 写 localStorage;不要求实时。
|
||||
|
||||
## 5. 手势一致性约定
|
||||
|
||||
### 5.1 全局默认映射
|
||||
|
||||
| 手势 | 全局语义 |
|
||||
| 手势 | 新手期 |
|
||||
|---|---|
|
||||
| 上滑 | 帮助 / 当前状态播报 |
|
||||
| 下滑 | 菜单(含:重听帮助、播报当前设置、重新开始、保存并回大厅) |
|
||||
| 单击 | 确认 / 继续 / 检查 |
|
||||
| 双击 | 重听(重播当前语音/线索/乐句) |
|
||||
| 左/右滑 | 选择 / 移动 |
|
||||
| 双击 | **不存在**。`doubleTapWindow: 0`。键盘回车按单击处理 |
|
||||
| 下滑 | 未解锁:`invalid` + 首次解释 |
|
||||
| 长按 | 未占用帮助时:旁白加速(12 号)。四向滑动是玩法时:长按=帮助,关闭加速 |
|
||||
|
||||
### 5.2 模态菜单约定(R3 修订:采纳 R2 开发实现,round2-review 裁决②)
|
||||
滑动、上滑:打断并执行。单击:只打断(跳句),不顺带执行「继续下一段」。
|
||||
|
||||
全球统一的模态菜单交互:**下滑呼出(模态)→ 单击循环切换选项(每切换播选项名)→ 双击确认执行 → 上滑=帮助/规则 → 下滑或"返回游戏"项关闭**。菜单打开时暂停计时类玩法(有计时器的游戏进入暂停态)。
|
||||
### 5.2 解锁阶梯(跨局记住,存进度或 `_settings`)
|
||||
|
||||
- 标准选项集:重新开始 / 回大厅(存档游戏为"保存并回大厅")/ 返回游戏;打开时先播 `menu_open` + 第一项。
|
||||
- 为什么单击=切换而非确认:结算页"单击=再来一局"已被占用,菜单内单击若作确认会与重开冲突;单击循环 + 双击确认把"浏览"与"执行"分离,误操作成本为零(escape/simon R2 已一致落地)。
|
||||
- **RPG《剑与声》豁免**:探索态菜单保持"左右滑切换 + 单击确认"——RPG 探索本身就是"左右滑选项 + 单击确认"范式,菜单与探索同构反而少学一套;战斗态不设菜单(下滑=逃跑)。
|
||||
- 选曲/存档确认等**非模态**选项界面(如 rhythm 选曲)不属于菜单,仍用"左右滑切换 + 单击确认"。
|
||||
| 阶段 | 条件 | 解锁 |
|
||||
|---|---|---|
|
||||
| 0 | 首次进入 | 单击、左右滑 |
|
||||
| 1 | 第一个小目标 | 上滑(或长按帮助,若滑动是玩法) |
|
||||
| 2 | 第一局结束 | 下滑=菜单 |
|
||||
| 3 | 累计 3 局 | 双击=重听**当前等待点完整句**(加「再说一遍:」)。禁止绑整段重播、重开、连跳 |
|
||||
| 4 | 大厅一键或专属教学 | 游戏专属高级手势 |
|
||||
|
||||
### 5.3 豁免表(以滑动为核心玩法的游戏)
|
||||
大厅提供「全部解锁」给老玩家。
|
||||
|
||||
四向滑动被玩法占用的游戏,"上滑=帮助 / 下滑=菜单"让位,偏离必须在开场交互教学中明确讲出:
|
||||
### 5.3 四向滑动是玩法:帮助换长按
|
||||
|
||||
| 游戏 | 滑动用途 | 帮助入口 | 菜单入口 |
|
||||
|---|---|---|---|
|
||||
| escape 暗室 | 四向滑=移动 | PLAY 中双击无目标时兜底播报目标与提示;卡关计时器自动三级提示 | 仅结算后下滑=模态菜单(PLAY 中无菜单,R3 打磨拟加双击二级入口) |
|
||||
| simon 音序回响 | 六手势全是答题输入 | 非输入阶段上滑=重听规则 | 结算后下滑=模态菜单 |
|
||||
| rhythm 节拍行者 | 四向滑=演奏输入 | 乐句间隙上滑=重听规则 | 结算后下滑=模态菜单 |
|
||||
| space 盲航 | 四向滑=闪避 | 坠毁结算后上滑=重听教学要点 | 结算后下滑=模态菜单 |
|
||||
| rpg 剑与声 | 左右滑=选择(符合默认) | 上滑=角色状态(符合默认) | 下滑=菜单(豁免:左右滑+单击,见 §5.2) |
|
||||
| storyline 声命线 | 左右滑=抉择(符合默认) | 上滑=帮助+进度(符合默认) | 下滑=菜单(R3 打磨统一到 §5.2 模态约定) |
|
||||
适用:escape、space、rhythm/drummer、dungeon、hunt,以及任何四向滑=移动/闪避/演奏的游戏。
|
||||
|
||||
### 5.4 通则
|
||||
- 帮助 = 长按。所有这类游戏同一条,不许再各换双击/上滑。
|
||||
- 菜单仍到阶段 2 才开放下滑;对局中下滑若与玩法冲突,对局中不开菜单,结算后开。
|
||||
- 新手期双击仍按单击处理。
|
||||
|
||||
- 任何游戏里,**做了一个手势 3 秒内必须有反馈**(引擎内置震动 + 内容音/语音),被判定无效的手势给 `error` 震动;教学阶段除外(教学里错误手势给纠正语音)。
|
||||
- 单击有 ~300ms 引擎级延迟:即时判定(格挡、节奏打击)一律绑滑动或双击,单击只用于非即时操作(确认、检查、菜单)。新设计继续遵守。**唯一例外**:rhythm 开启引擎 `immediateTap`(按下即发 tap、双击补发改判),因它的单击就是核心演奏输入;其他游戏不得开(每次按下都先发 tap,会污染滑动/长按语义)。
|
||||
- 结算画面统一:单击=再来一局,下滑=菜单(回大厅)。教学可跳过:任何游戏的引导阶段,下滑=跳过引导(首次强制完整引导的标志位存进度里)。
|
||||
**六手势都是音色/答题(simon)**:帮助也换长按;音色按实力渐进开放,一次只学一样。
|
||||
|
||||
### 5.5 键盘平行通道(P0-A 已实现:engine/gesture.js 内置通道)
|
||||
### 5.4 模态菜单(阶段 2 以后)
|
||||
|
||||
> 调研与业界依据:[research/platform/02-input-parity.md](../../research/platform/02-input-parity.md)(audiogames.net 社区惯例、A Blind Legend / Blind Drive 双端先例)。
|
||||
**下滑呼出 → 左右滑切换(每项报名)→ 单击确认 → 上滑或长按=重听菜单说明 →「返回游戏」或再下滑关闭。**
|
||||
|
||||
PC 键盘是触屏手势的**平行输入通道**,不是另一套手势宪法:键盘事件在
|
||||
`attachGestures` 内部喂入与 touch/mouse **同一状态机**,游戏层收到的
|
||||
7 种手势事件(up/down/left/right/tap/doubletap/longpress/longpressend
|
||||
+ immediateTap 的 tapcancel)与内置震动**完全同构**——游戏代码零改动,
|
||||
§5.1-§5.4 的全部手势语义(含各游戏豁免表)原封不动。
|
||||
废止「单击循环 + 双击确认」。原因:新手期没有双击;单击的全局含义是确定,菜单里不应改成切换。
|
||||
|
||||
**键位表(裁定方案,`e.code`):**
|
||||
标准选项:重新开始(破坏性,二次确认)/ 保存并回大厅 / 返回游戏。打开时暂停计时玩法。
|
||||
|
||||
| 手势(§5.1 语义不变) | 键盘主键 | 别名 | 行为差异 |
|
||||
|---|---|---|---|
|
||||
| 左滑 / 右滑 | ← / → | A / D | keydown 即发(无位移/速度判定,零延迟) |
|
||||
| 上滑 / 下滑 | ↑ / ↓ | W / S | 同上 |
|
||||
| 单击 | 空格 | — | 走完整 tap 状态机:**保留 ~300ms 双击窗**(与触屏单击同感) |
|
||||
| 双击 | **回车** | 空格×2 | 回车**即时**触发(不等双击窗);空格两连也判双击(状态机路径) |
|
||||
| 长按 / 长按结束 | 按住空格 ≥450ms / 松开 | — | 与触摸长按完全一致(含旁白快进 window 事件) |
|
||||
RPG 探索菜单与探索同构:左右滑 + 单击,符合本条。战斗态下滑=逃跑,不设菜单。
|
||||
|
||||
设计裁定(P0-A,均已实现并回归):
|
||||
选曲等非模态选项界面:左右滑 + 单击,不变。
|
||||
|
||||
1. **空格也走 300ms 双击窗**(与触摸共享窗口,混合设备"触屏 tap + 空格
|
||||
tap"判 doubletap = 同一虚拟指针语义);**回车是唯一的即时双击键**——
|
||||
确认类操作零延迟,同时保留空格×2 兼容触屏肌肉记忆。
|
||||
2. **不做 Esc 映射**:下滑已覆盖菜单语义(§5.1/§5.2),Esc 留给浏览器
|
||||
自身/未来全屏退出,不进入手势域。
|
||||
3. **守卫**:`e.repeat` 抑制(按住只发一次);映射键 preventDefault
|
||||
(防滚页/焦点激活);表单控件焦点(input/textarea/select/
|
||||
contenteditable)放行;未映射键(Tab 等)不拦截;tracking 单飞行
|
||||
指针互斥(与多指忽略一致)。
|
||||
4. **提示随输入模式**(settings.input,见 §1.1):三通道永远并行在线,
|
||||
模式只切提示文案(遮罩「轻触开始」/「按空格开始」),供后续游戏内
|
||||
提示与语音变体(input-parity 路线 a)接入。
|
||||
5. 遮罩键盘解锁:空格/回车 keydown 即可解锁音频(audio.js
|
||||
showStartOverlay),PC 玩家全程无需鼠标。
|
||||
6. 测试:`web/harness/engine-input.test.mjs`(61 断言);live 管线
|
||||
`POST /gesture {"keyboard":true,"key":"ArrowLeft"|"Space"|"Enter"}`
|
||||
或 `{"type":"tap","keyboard":true}`(CDP Input.dispatchKeyEvent,
|
||||
会话剧本加 `keyboard:true` 即可键盘复跑)。
|
||||
结算:单击=再来一局;菜单已解锁则下滑=菜单。
|
||||
|
||||
## 6. 向导层(R7 增补,已实现:engine/guide.js)
|
||||
### 5.5 通则
|
||||
|
||||
> 设计裁定与台词表全录:[14-guide-layer.md](14-guide-layer.md)。本节只列与全局约定交叉的部分。
|
||||
- 矩阵无空格:每个「可感知状态 × 已解锁手势」都必须有声音(回执或内容音)。见各游戏设计单。
|
||||
- 连点/乱滑不绑定破坏性操作。
|
||||
- 引导可跳过:已完成过引导的玩家,开场用一句问「点一下开始」;重听引导放到帮助手势,不占用下滑(新手期下滑未解锁)。
|
||||
- `immediateTap` 仅 rhythm/drummer 演奏期。新手期其他游戏用 `doubleTapWindow: 0` 获得即时单击,不要开 immediateTap。
|
||||
- 教学:第一句话就动手;一次只教一个;做对立刻肯定(≤4 字)并进入下一步,禁止成功后再灌补救。
|
||||
|
||||
1. **四个全局机制**(方法论 research/02 §3 的 L3/L4 落地):状态签名 earcon(6 状态+2 功能音,运行时合成,全项目统一词表);回合标记 `turn`(等待输入开始处);静默看门狗(等待输入无操作→轻提醒→升级上下文提示,用尽即停不轰炸);纠错 `error`(error 震+一句"该做什么")。
|
||||
2. **等级语义**:`full`=earcon+向导语音+震动;`standard`=earcon+震动(**无向导语音**);`off`=全部 no-op 且不注册定时器。向导语音一律 `queue:true`,**绝不顶掉在播对白**(A3 信息分层)。
|
||||
3. **与既有约定的边界**:向导不改变任何手势映射与玩法判定;向导震动只用既有震型(confirm/error/nudge 复用),不新增语义震;向导 earcon 是**系统音**(P2 系统音/叙事音分离),不占用 sfx 内容音语义域。
|
||||
4. **看门狗通用参数**(各游戏已按此接):第 1 级 8~10s(nudge+一句提示),第 2 级 20~25s(上下文提示/复述),之后停止;玩家任意手势复位。escape 三级卡关计时器(60/120/180s)保持独立,不受影响。
|
||||
5. **测试约定**:既有 playtest 一律 `settings.set({guide:'off'})` 验证纯玩法逻辑;向导行为由 `web/harness/guide.test.mjs`(full 档)覆盖。
|
||||
### 5.6 键盘平行通道
|
||||
|
||||
键位表不变(方向键/WASD=滑,空格=单击,回车=双击,按住空格=长按)。
|
||||
|
||||
新手期差异:
|
||||
- `doubleTapWindow: 0` 时触屏与空格均立即单击。
|
||||
- 回车仍发 `doubletap`:游戏层在新手期把它当成 `tap`。
|
||||
- 提示文案随 `settings.input`:触屏说「点一下」,键盘说「按空格」。
|
||||
|
||||
守卫、遮罩解锁、测试约定沿用原实现。
|
||||
|
||||
---
|
||||
|
||||
## 6. 发言权、等待声、向导
|
||||
|
||||
实现骨架见 26 号 §4.1~§4.6;接线裁定见 [14-guide-layer.md](14-guide-layer.md)。
|
||||
|
||||
| Floor 状态 | 听感 | 玩家操作 |
|
||||
|---|---|---|
|
||||
| `SPEAKING` | 语音;BGM 整链压低;句间不起等待声 | 可打断句:立刻停,按 §5.1 处理;关键句:`busy` |
|
||||
| `YOUR_TURN` | 交接提示音 `turn` → 400ms 后等待声,直到操作 | 等待声 80ms 淡出,交给游戏 |
|
||||
| `BUSY` | 只有内容演出,无等待声 | `busy` |
|
||||
| `ACTION` | 玩法声本身就是状态(节奏、闪避、探索环境音常驻) | 直接交给游戏 |
|
||||
|
||||
等待声:合成、轻、全项目一套(26 §4.1 起步参数)。剧情类可用很轻的环境循环替代,但必须全游戏统一。
|
||||
|
||||
迷茫:从乱点/连无效/反复重听识别,三级接管(短提示 → 只留一个手势 → 自动演示)。静默看门狗只负责「不动」:动作类 5~8s,剧情类 15~20s,最多两级后安静,只留等待声。
|
||||
|
||||
状态签名 earcon(menu/explore/battle/choice/settle/danger + turn/nudge)保留。新手期只教玩家能感知的 ≤3 种,第一次出现配一句解释。
|
||||
|
||||
---
|
||||
|
||||
## 7. 横切验收(每款游戏开工前)
|
||||
|
||||
设计单必须交齐 26 号附录 C:一句话核心动作、≤3 个可感知状态、新手手势与解锁、状态×手势矩阵、等待点、首 3 分钟逐秒脚本、失败表、台词类别、断点复述句。
|
||||
|
||||
合格指标见 26 §6.4。出现 26 §7 任一反模式,设计不通过。
|
||||
|
||||
Reference in New Issue
Block a user