第二批反馈:引擎改造(限幅/SoundTouch不变调变速/长按快进/跳句/iOS闪光降级) + 6游戏状态BGM与试玩测试全绿
This commit is contained in:
@@ -37,7 +37,7 @@
|
||||
|
||||
### storyline《声命线》
|
||||
|
||||
- voice 双性别版(male/ 与 female/ 各 36 条):旁白 + 系统音 = `help menu status1 status2 status3 p1–p8 n00_intro n01_wake n04_exit n05_signal n06_whistle n08_vent n09_dead n10_rain n11_child n13_leave n14_ignore n15_bridge n16_culvert n16b_culvert_c n17_cable n17b_cable_c n20_convoy n22_fight n23_tower e1_dawn e2_price e3_alone e4_static`
|
||||
- voice 双性别版(male/ 与 female/ 各 37 条(R6 +`skip_hint`):旁白 + 系统音 = `help menu status1 status2 status3 p1–p8 n00_intro n01_wake n04_exit n05_signal n06_whistle n08_vent n09_dead n10_rain n11_child n13_leave n14_ignore n15_bridge n16_culvert n16b_culvert_c n17_cable n17b_cable_c n20_convoy n22_fight n23_tower e1_dawn e2_price e3_alone e4_static`
|
||||
- voice 角色台词(**不做双性别**,沿用平铺原文件):
|
||||
|
||||
| 角色 | speaker | 文件 id |
|
||||
@@ -50,45 +50,52 @@
|
||||
|
||||
约定:角色台词在两个性别目录下使用**同一份文件**(由开发复制/链接或引擎回退到平铺目录,见 round1-report)。
|
||||
- sfx(12):`footsteps gunshot heartbeat radio_static rubble signal_beep struggle ui_confirm ui_menu water whistle wind`
|
||||
- bgm(1):`dark_drone`
|
||||
- bgm(2):`dark_drone`(剧情)+ R6 新增 `menu`(菜单 pad,-24 LUFS 档)
|
||||
|
||||
### escape《暗室》(R2 重设计版,最终清单见 `round2-voice-ids.md`)
|
||||
|
||||
- voice 双性别版(male/ 与 female/ 各 74 条):引导 `g0_intro g1_move g1_done g2_wall g3_left g4_down g5_inspect g5_key g6_doubletap g6_done g7_goal`、引导纠错 `guide_wrong_* guide_blunt_* guide_offpath guide_skip reopen_prompt`、三级提示 `stuck_ask stuck_{key,cabinet,box,gate}_{1,2,3}`、导航 `nav_{up,down,left,right}`、房间 `room_{storage,cabinet,power,gate}`、用时 `time_band1–4`、保留句 `wall start_room found_key inspect_* unlock_cabinet box_fixed fix_box escape use_fail inv_* replay again empty_1–3`、菜单 `help_ops menu_*`
|
||||
- voice 双性别版(male/ 与 female/ 各 75 条(R6 +`skip_hint`):引导 `g0_intro g1_move g1_done g2_wall g3_left g4_down g5_inspect g5_key g6_doubletap g6_done g7_goal`、引导纠错 `guide_wrong_* guide_blunt_* guide_offpath guide_skip reopen_prompt`、三级提示 `stuck_ask stuck_{key,cabinet,box,gate}_{1,2,3}`、导航 `nav_{up,down,left,right}`、房间 `room_{storage,cabinet,power,gate}`、用时 `time_band1–4`、保留句 `wall start_room found_key inspect_* unlock_cabinet box_fixed fix_box escape use_fail inv_* replay again empty_1–3`、菜单 `help_ops menu_*`
|
||||
- voice 已删除(R2):`n0–n9 nshi unit_min unit_sec time_prefix intro tutorial hint_key hint_cabinet hint_box hint_gate`(整句化替代);平铺 `voice/` 旧文件全部移除
|
||||
- sfx(16):`amb_drip amb_hum amb_wind`(保留)+ R2 新增 `amb_storage amb_cabinet amb_power amb_gate amb_gate_live`(Stable Audio 3,6s,统一 -25dB 均值,storage/power 偏左、cabinet 偏右 pan)+ `door_creak gate_open pickup power_on spark step unlock wall win_chime`;已删除 `ui_deny`(反馈改震动)
|
||||
- bgm(1):`drone`
|
||||
- bgm(2):`drone`(探索)+ R6 新增 `menu`(菜单/结算 pad)
|
||||
|
||||
### simon《音序回响》(R2 重设计版,最终清单见 `round2-voice-ids.md`)
|
||||
|
||||
- voice 双性别版(male/ 与 female/ 各 68 条):交互教学 `t0_welcome t0_goal t1_up–t6_double t_try t_ok t_wrong_* t_blunt_* t7_ready t7_retry t_skip`、轮次 `round_01–round_20 round_more`(整句)、成绩 `score_band1–6`(整句)、流程 `your_turn chances_out retry_use relisten replay rules_prompt rules gameover`、反馈 `correct wrong chance_plus new_record`、菜单 `menu_*`
|
||||
- voice 双性别版(male/ 与 female/ 各 69 条(R6 +`skip_hint`):交互教学 `t0_welcome t0_goal t1_up–t6_double t_try t_ok t_wrong_* t_blunt_* t7_ready t7_retry t_skip`、轮次 `round_01–round_20 round_more`(整句)、成绩 `score_band1–6`(整句)、流程 `your_turn chances_out retry_use relisten replay rules_prompt rules gameover`、反馈 `correct wrong chance_plus new_record`、菜单 `menu_*`
|
||||
- voice 已删除(R2):`di lun num_shi num_0–num_9 score_pre best_pre`(拼接件)+ `intro teach_* listen`(旧连播教学);平铺 `voice/` 旧文件全部移除
|
||||
- sfx(7):`gameover tone_doubletap tone_down tone_left tone_right tone_tap tone_up`;已删除 `correct wrong newrecord`(反馈改震动)
|
||||
- bgm:**已于 R1 按用户要求移除**(原 `theme`,代码引用由开发删除)
|
||||
- bgm:游玩**无 BGM**(用户要求);R6 新增 `menu`(菜单/结算极轻 pad,volume 0.3,10 文档 §4)
|
||||
|
||||
### rhythm《节拍行者》(R3 重构版,台词依据 `docs/design/03-rhythm-voice-ids.md`)
|
||||
|
||||
- voice 双性别版(male/ 与 female/ 各 31 条):开场流程 `welcome welcome_back tut_1 tut_2 tut_3 tut_done tut_skip mid_song`、教学纠正 `retry_early retry_late retry_gesture retry_listen retry_skip`、选曲解锁 `select_hint song1_name song2_name song3_name song_locked unlock_song2 unlock_song3`、结算 `grade_s grade_a grade_b grade_c new_best_combo restart`、菜单规则 `rules settings_hint menu_main menu_resume menu_lobby`
|
||||
- voice 双性别版(male/ 与 female/ 各 32 条(R6 +`skip_hint`):开场流程 `welcome welcome_back tut_1 tut_2 tut_3 tut_done tut_skip mid_song`、教学纠正 `retry_early retry_late retry_gesture retry_listen retry_skip`、选曲解锁 `select_hint song1_name song2_name song3_name song_locked unlock_song2 unlock_song3`、结算 `grade_s grade_a grade_b grade_c new_best_combo restart`、菜单规则 `rules settings_hint menu_main menu_resume menu_lobby`
|
||||
- voice 已删除(R3):`tut_start`(平铺旧 id 全部移除,其余旧 id 均在 R2 已替换)
|
||||
- voice 修订(R5):`menu_main` 改词重录为「菜单。单击切换选项,双击确认。」(对齐 round2-review 裁决②全球菜单约定;选曲界面非模态菜单不受影响)
|
||||
- sfx(7,R3 补齐):`inst_kick inst_snare inst_hat_l inst_hat_r inst_tom_hi inst_tom_lo inst_accent`(演奏乐器音,详见 round3-report §7;hat_l 闭合镲极左 / hat_r 开放镲极右,accent 为 A minor 合成亮音);已删除 `judge_* tick tick_accent`(R3)与 `cue_*`(R3 收尾,重构不再使用指令音)
|
||||
- bgm(3,R3 重制):`track90`(90.01 BPM,85.33s)`track105`(104.99 BPM,73.14s)`track120`(120.00 BPM,72.00s),A minor 电子乐,整数小节无缝循环,loudnorm -20 LUFS;旧 `groove` 已删除
|
||||
- bgm(3,R3 重制):`track90`(90.01 BPM,85.33s)`track105`(104.99 BPM,73.14s)`track120`(120.00 BPM,72.00s),A minor 电子乐,整数小节无缝循环,loudnorm -20 LUFS;旧 `groove` 已删除;R6 新增 `menu`(选曲/结算 pad)
|
||||
|
||||
### space《盲航》(R3 备产,台词依据 `docs/design/04-space-voice-ids.md`)
|
||||
- voice 双性别版(male/ 与 female/ 各 52 条):演练 `drill_*`(14)、保护期 `protect_*`(5)、功能引入 `feat_* shield_ready shield_block`(6)、被撞归因 `hit_*`(5)、里程碑 `ms_10 ms_25 ms_50 ms_100`、结算 `time_1–4 dodge_1–4 new_record restart_hint`、菜单系统 `second_run_ask menu_* help_recap settings_hint paused`
|
||||
- voice 双性别版(male/ 与 female/ 各 53 条(R6 +`skip_hint`):演练 `drill_*`(14)、保护期 `protect_*`(5)、功能引入 `feat_* shield_ready shield_block`(6)、被撞归因 `hit_*`(5)、里程碑 `ms_10 ms_25 ms_50 ms_100`、结算 `time_1–4 dodge_1–4 new_record restart_hint`、菜单系统 `second_run_ask menu_* help_recap settings_hint paused`
|
||||
- voice 修订(R4):`menu_main` 改词重录为「菜单。单击切换选项,双击确认。」(对齐 round2-review 裁决②全球菜单约定)
|
||||
- voice 已删除(R3):`num0–9 num_shi num_bai n_time n_sec n_dodge n_ge n_milestone intro1–4 hit1 hit2 gameover restart`(数字拼接与旧教学弃用);平铺旧文件全部移除
|
||||
- sfx(12):`alarm boost crash dodge hit shield shield_block whoosh_down whoosh_left whoosh_right whoosh_up`
|
||||
- bgm(1):`engine`
|
||||
- bgm(2):`engine`(对局)+ R6 新增 `menu`(菜单/结算 pad)
|
||||
|
||||
### rpg《剑与声》(R4 新游戏第一章,台词依据 `docs/design/05-rpg-ch1-voice-ids.md` + `05-rpg-addendum.md`)
|
||||
|
||||
- voice 旁白双性别版(male/ 与 female/ 各 108 条,male=Uncle_Fu 说书人 / female=Serena 武侠故事):序章 `intro_1–3`、系统状态 `sys_* help_* settings_hint st_*`、场景 `desc_*`(16)、选项 `opt_*`(18)、事件 `evt_*`(6)、战斗 `btl_* cmd_* tut_*`(27,含 R5 补录 `btl_half_bandit`)、商店 `shop_*`(7)、敌方档位 `foe_hp_high/mid/low`(addendum §6.2 补录)
|
||||
- voice 旁白双性别版(male/ 与 female/ 各 113 条,male=Uncle_Fu 说书人 / female=Serena 武侠故事):序章 `intro_1–3`、R6 新增首次战斗教学 `tut_battle_1–5`、系统状态 `sys_* help_* settings_hint st_*`、场景 `desc_*`(16)、选项 `opt_*`(18)、事件 `evt_*`(6)、战斗 `btl_* cmd_* tut_*`(27,含 R5 补录 `btl_half_bandit`)、商店 `shop_*`(7)、敌方档位 `foe_hp_high/mid/low`(addendum §6.2 补录)
|
||||
- voice NPC 单音色平铺(14 条,落 `voice/` 根,引擎平铺回退):村长 `npc_headman_1–4`(Uncle_Fu·慈祥和缓)、老猎人 `npc_hunter_1–4`(Eric·沙哑豪爽)、寨丁头目 `npc_elite_1/half/die`(Dylan·凶狠)、黑风寨主 `npc_boss1_1/2/die`(Uncle_Fu·低沉阴狠,与村长同 speaker 不同 instruct)
|
||||
- sfx(35):前摇 `tel_wolf tel_bandit tel_spider tel_elite tel_boss1 tel_croc tel_shaman tel_puppet tel_boss2`(1.0s 格挡窗口);战斗 `atk_swing atk_hit parry skill_slash enemy_die potion` + SYN `hurt flee`;探索 `chest drink_water rest door_heavy` + SYN `step coin levelup`;环境 `amb_village amb_path amb_fork amb_chest amb_stream amb_hunter amb_deepwood amb_gate amb_hall amb_swamp amb_peak`(5s 无缝循环,均值 -25dB);`ui_deny` 按设计不做
|
||||
- bgm(4,Mureka):`village battle boss ending`(90s 无缝循环,loudnorm -20);探索期无音乐(addendum §3),`amb_*` 由游戏层手动 loop 接 sfx 总线
|
||||
- bgm(6,Mureka):`village battle boss ending`(R4)+ R6 新增 `menu`(菜单 pad)与 `explore`(探索轻垫乐,10 文档 §7 恢复,volume 0.35);90s 无缝循环;`amb_*` 由游戏层手动 loop 接 sfx 总线
|
||||
- 再生成方法见 `web/rpg/gen/README.md`
|
||||
|
||||
## 响度与爆音标准(R6 起)
|
||||
|
||||
- sfx one-shot:峰值归一 **-3dBFS**(真峰值经 ogg 解码回读校验,见 round6-report §1);首尾 8ms cos² 淡入淡出;去直流。
|
||||
- loop(amb_*/bgm):首尾交叉淡化保证循环连续,不加淡入淡出;仅做直流/峰值检查。
|
||||
- voice:沿用 R1 峰值 0.89 归一策略,不动。
|
||||
- bgm:loudnorm -20 LUFS(主题曲)/ -24 LUFS(menu pad)。
|
||||
|
||||
## 发音质量
|
||||
|
||||
### 本轮已采取的规避措施
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
| 游戏 | ogg | m4a | 0字节 | 解码失败 | voice male/female id 一致 |
|
||||
|---|---|---|---|---|---|
|
||||
| storyline | 133 | 133 | 0 | 0 | ✅ 各 36(平铺 48 个角色/NPC 句,豁免) |
|
||||
| escape | 166 | 166 | 0 | 0 | ✅ 各 74 |
|
||||
| simon | 143 | 143 | 0 | 0 | ✅ 各 68 |
|
||||
| rhythm | 72 | 72 | 0 | 0 | ✅ 各 31 |
|
||||
| space | 116 | 116 | 0 | 0 | ✅ 各 52 |
|
||||
| rpg | 269 | 269 | 0 | 0 | ✅ 各 108(平铺 14 个角色/NPC 句,豁免) |
|
||||
| storyline | 136 | 136 | 0 | 0 | ✅ 各 37(平铺 48 个角色/NPC 句,豁免) |
|
||||
| escape | 169 | 169 | 0 | 0 | ✅ 各 75 |
|
||||
| simon | 146 | 146 | 0 | 0 | ✅ 各 69 |
|
||||
| rhythm | 75 | 75 | 0 | 0 | ✅ 各 32 |
|
||||
| space | 119 | 119 | 0 | 0 | ✅ 各 53 |
|
||||
| rpg | 283 | 283 | 0 | 0 | ✅ 各 114(平铺 14 个角色/NPC 句,豁免) |
|
||||
|
||||
## 结论
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
## 附注
|
||||
|
||||
- storyline 平铺 48 个 = 12 个角色台词(林晚/猎狗/小满/林晨/广播,单音色永久保留)+ 36 个 R1 旁白旧文件(与 male/ 内容重复的遗产,待引擎切换验证后清理,见 round1-report §2)。
|
||||
- rpg 平铺 14 个 = NPC 句(设计如此,单音色)。
|
||||
- 终检脚本:`tools/check_all_assets.py`(可重复执行)。
|
||||
- storyline 平铺 = 角色台词(单音色永久保留)+ R1 旁白旧文件(遗产,待清理)。
|
||||
- rpg 平铺 = NPC 句(设计如此,单音色)。
|
||||
- R6 起 sfx 峰值标准为 -3dBFS(真峰值经解码回读校验);voice 目录响度策略不变(峰值 0.89)。
|
||||
- 终检脚本:`tools/check_all_assets.py`;爆音扫描/修复:`tools/scan_clicks.py` / `tools/fix_clicks.py`。
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# R6 音频轮次报告(2026-08-30,音乐音效总监)
|
||||
|
||||
本轮主题:爆音资产排查修复 + 状态 BGM 7 首 + RPG 战斗教学/全局跳过提示语音。Mureka 本轮 $0.21 / $1.00,**累计 $0.63 / $2.00**。
|
||||
|
||||
## 1. 爆音排查与修复
|
||||
|
||||
**工具**:`tools/scan_clicks.py`(扫描)/ `tools/fix_clicks.py`(修复),全程可复跑;原件备份在 `tools/asset_fix_backup/`(71 个文件)。
|
||||
|
||||
**扫描口径**:峰值 >-1dBFS / 首尾电平突变(首末 1ms 幅值 > 局部 50ms 峰值 15%,局部低于 -40dB 的静音区不判)/ 直流偏置 |DC|>0.001。voice 目录按任务要求**不动**(峰值 0.89 归一策略保留)。
|
||||
|
||||
**初扫结果(899 个 ogg 全量)**:
|
||||
|
||||
| 类别 | 数量 | 说明 |
|
||||
|---|---|---|
|
||||
| sfx/bgm 峰值过热 | 27 | 其中 rpg 15 个 SA3 one-shot 解码峰值高达 +0.9~+6.6dBFS(真·爆音源) |
|
||||
| sfx/bgm 直流偏置 | 43 | 最大 0.076(rpg/atk_swing) |
|
||||
| sfx/bgm 首尾突变 | 48 | 老资产无淡入淡出(storyline/escape/simon/space 为主) |
|
||||
| voice 过热 | 340 | 不修(语音响度策略不动,见任务说明) |
|
||||
|
||||
**根因发现(重要)**:R4 的 rpg SA3 one-shot 源是近满幅高密度波形(rms 0.84 / 峰值 0dBFS,>15kHz 能量 22%),MDCT 有损编码(vorbis/aac/opus 全部)重建时过冲 +4~8dB——ffmpeg `volumedetect` 走 s16 中间格式把超幅削到 0.0dB 显示,**之前的 QC 完全没发现**。本轮修复 encode 环节改为「编码→解码回读真峰值→超 -3dB 则降增益 + 首轮 18kHz 低通→重编」(最多 3 次迭代)。
|
||||
|
||||
**修复结果**:71 个 sfx/bgm 文件重处理(storyline 10 / escape 10 / simon 7 / rhythm 7 / space 11 / rpg 26),统一标准:one-shot 去直流 + 首尾 8ms cos² 淡入淡出 + 峰值 -3dBFS(真峰值校验后);loop(amb_*/bgm)只去直流(交叉淡化循环不加首尾淡入淡出,避免破坏循环)。rpg one-shot 从 staging 无损 wav 重做,其余从备份初代源修复(避免多次有损转码)。
|
||||
|
||||
**复扫(终态)**:sfx/bgm 99 个 —— 过热 0 / 直流 0 / 首尾突变 0。**全绿。**
|
||||
|
||||
## 2. 状态 BGM(7 首,docs/design/10-feedback2-state-bgm.md)
|
||||
|
||||
| 资产 | task id | 响度 | 成品 |
|
||||
|---|---|---|---|
|
||||
| storyline `bgm/menu` | 158096439705601 | -24 LUFS(menu pad 档) | 90s 循环,mean -24.4dB |
|
||||
| escape `bgm/menu` | 158096580149249 | -24 | mean -26.1dB |
|
||||
| simon `bgm/menu` | 158096714629126 | -24(引擎再按 volume 0.3) | mean -25.8dB |
|
||||
| rhythm `bgm/menu` | 158096850812929 | -24 | mean -25.3dB |
|
||||
| space `bgm/menu` | 158097039425538 | -24 | mean -25.1dB |
|
||||
| rpg `bgm/menu` | 158097182294017 | -24 | mean -25.9dB |
|
||||
| rpg `bgm/explore`(恢复) | 158097360420865 | -20(引擎 volume 0.35) | mean -22.3dB |
|
||||
|
||||
全部一次成功选候选 0;强 onset 起点 + 90s + 3s crossfade 无缝循环 + ogg q3/m4a。既有主题曲全部不动(storyline dark_drone、escape drone、rhythm track90/105/120、space engine、rpg village/battle/boss/ending)。状态→BGM 映射与切换时机以 10 文档 §2-§7 为准。
|
||||
|
||||
## 3. 新语音(22 条,双性别)
|
||||
|
||||
| id | 游戏 | 条数 | 文案 |
|
||||
|---|---|---|---|
|
||||
| `tut_battle_1..5` | rpg | 5×2 | 首次战斗教学:回合制说明 / 左右滑选招式单击出手 / 听前摇双击格挡 / 防御减半与金疮药 / 开场收束 |
|
||||
| `skip_hint` | 全 6 游戏 | 1×2×6 | 「单击可跳过旁白。」(各游戏既有 instruct 常量) |
|
||||
|
||||
均已合入 `tools/gen_voice_dual.py` 台词表并落盘 male/female 双格式。rpg 旁白现 113 id ×2(+NPC 14 平铺)。
|
||||
|
||||
## 4. 给游戏层的接线约定
|
||||
|
||||
1. **菜单/结算音乐**:所有游戏统一 `bgm/menu` id;切换时机与淡入时长按 10 文档逐游戏表(storyline 500ms、escape 400ms/结算 1500ms、simon 600ms/结算延后 1000ms、rhythm 800ms、space 300ms、rpg 战斗 400ms 快切)。
|
||||
2. simon 游玩全程不得加载任何 bgm;`bgm/menu` 仅菜单与结算,volume 0.3。
|
||||
3. rpg 双层:BGM 层报状态(menu/explore/village/battle/boss/ending),sfx 层 amb 报场景(手动 loop 接 `_sfxBus`,不变);胜利过渡 = battle 淡出 1500ms → explore 淡入 2000ms。
|
||||
4. `tut_battle_1..5`:首场战斗(enc_teach_wolf)B_START 时按序链播,二周目起跳过;`skip_hint` 为备选通用句,接入与否由游戏层定。
|
||||
5. `bgm=0` 时全部状态音乐不加载(含 menu pad 与 space engine——10 文档 §1.5 裁定)。
|
||||
|
||||
## 5. 复跑与终检
|
||||
|
||||
- `tools/check_all_assets.py` 终检已更新(`docs/audio/final-asset-check.md`):928 ogg + 928 m4a,双格式/0 字节/解码/性别集合一致性全绿。
|
||||
- 遗留:voice 层 340 个文件峰值 >-1dBFS 属 R1 既定归一(0.89 峰值),非爆音(有 TTS 天然淡入);如需统一可考虑 R7 评估,但会破坏既有响度平衡,不建议。
|
||||
@@ -0,0 +1,93 @@
|
||||
# 10 · 全局"状态即音乐"规范(state-driven BGM,音频总监生产依据)
|
||||
|
||||
> **给音频总监的生产摘要**:本轮新增 7 条 BGM——每游戏一条 `bgm/menu`(6 条)+ RPG 恢复 `bgm/explore`(1 条)。各游戏 prompt 草稿见 §8。所有新 BGM:60-90s 无缝循环、-20 LUFS、ogg+m4a 双格式、归一化工艺沿用现有管线。
|
||||
> **给开发的摘要**:状态→BGM 映射表见 §2-§7(逐游戏)。切换全部走引擎 `play('bgm/...')` 交叉淡入(默认 800ms),特例见各表"切换"列。`bgm=0` 设置时全部静默(含 menu pad)。RPG 的探索 amb 环境音保持在 sfx 层 loop(05-rpg-addendum §3 不变),**BGM 层专用于状态音乐**——两层叠加正是"听 BGM 辨状态、听 amb 辨场景"的设计意图。
|
||||
|
||||
---
|
||||
|
||||
## 1. 总则
|
||||
|
||||
1. **每个可感知状态都要有 BGM 身份**:菜单/结算 = `bgm/menu`(轻 pad);游玩 = 各游戏既有主题曲;战斗/Boss(RPG)= 专属曲。玩家闭上眼只听 2 秒音乐,就该知道自己在菜单里还是在游戏里。
|
||||
2. **menu pad 的共性要求**:音量基底 -24 LUFS(比主题曲低一档)、无鼓点或极弱脉冲、和声静止(pad 性质)、长度 ≥60s 无缝循环。它是"系统界面"的声音,不能抢戏。
|
||||
3. **simon 特例**:游玩/教学/序列播放**全程无 BGM**(用户明确要求,02 文档既定)。只在菜单与结算挂 `bgm/menu`,且以 volume 0.3 播放(比别的游戏更轻)。
|
||||
4. 切换时机一律在**状态进入时**(不是退出时);语音 ducking 行为不变(voice 播放时 BGM duck 到 20%)。
|
||||
5. `bgm=0`(设置关闭)时:所有状态音乐不加载不播放;RPG 场景 amb(sfx 层)不受影响;space 的 `bgm/engine` 属内容音?——**裁定:engine 是 BGM 层资产,bgm=0 时静默**,盲航的方位信息全部由 whoosh/alarm(sfx)承载,无信息损失。
|
||||
|
||||
## 2. storyline《声命线》
|
||||
|
||||
| 状态 | BGM | 切换 |
|
||||
|---|---|---|
|
||||
| 剧情播放(含抉择) | `bgm/dark_drone`(保留) | 开局即播,全剧不切 |
|
||||
| 菜单(下滑呼出) | `bgm/menu` | 进菜单 crossfade 500ms;关菜单淡回 dark_drone 800ms |
|
||||
| 结局结算 | 保持 `bgm/dark_drone` 不切 | 结局语音 duck 即可,氛围连贯 |
|
||||
|
||||
## 3. escape《暗室》
|
||||
|
||||
| 状态 | BGM | 切换 |
|
||||
|---|---|---|
|
||||
| 引导 + 自由探索 | `bgm/drone`(保留) | 不变 |
|
||||
| 菜单(ENDING 下滑呼出) | `bgm/menu` | 进菜单 crossfade 400ms |
|
||||
| 逃脱结算(ENDING) | `bgm/menu`(volume 0.5) | 现有 `stopBgm(2500)` 淡出 drone 后,escape 语音播完淡入 menu pad 1500ms——结算画面从"空洞的静"变成"松一口气的亮" |
|
||||
|
||||
## 4. simon《音序回响》(特例)
|
||||
|
||||
| 状态 | BGM | 切换 |
|
||||
|---|---|---|
|
||||
| 教学 / 对局全流程 | **无**(静默) | 不加载任何 bgm |
|
||||
| 菜单(结算后下滑) | `bgm/menu`(volume 0.3) | 淡入 600ms |
|
||||
| 结算(gameover) | `bgm/menu`(volume 0.3) | sfx/gameover 播完 1s 后淡入 1000ms |
|
||||
| 单击重开 | 停 menu pad | `stopBgm(300)`,回静默 |
|
||||
|
||||
## 5. rhythm《节拍行者》
|
||||
|
||||
| 状态 | BGM | 切换 |
|
||||
|---|---|---|
|
||||
| 曲目游玩(含教学) | `bgm/track90/105/120`(不动) | 现有手动网格排程不变 |
|
||||
| 选曲界面 | `bgm/menu` | 进选曲淡入 800ms;选定曲目后 stopBgm(400) 再按现有网格起曲目 BGM |
|
||||
| 模态菜单(暂停) | 现有断点续播机制**保留**,menu pad **不叠**——暂停 = 音乐停(实现已如此,是最干净的"暂停感") | 不变 |
|
||||
| 结算 | 曲目 BGM 现有 0.6s 淡出后,评级语音播完淡入 `bgm/menu` 800ms | 新增 |
|
||||
|
||||
## 6. space《盲航》
|
||||
|
||||
| 状态 | BGM | 切换 |
|
||||
|---|---|---|
|
||||
| 演练 + 对局 | `bgm/engine`(保留) | 不变 |
|
||||
| 模态菜单(暂停) | `bgm/menu` | 进菜单 crossfade 300ms(暂停要快);回对局淡回 engine 500ms |
|
||||
| 坠毁结算 | 现有 stopBgm(600) 后,结算语音链播完淡入 `bgm/menu` 800ms | 新增 |
|
||||
|
||||
## 7. rpg《剑与声》(重点:听觉状态语言)
|
||||
|
||||
用户要求"通过背景音乐判断当前处于菜单/地图/战斗状态"。RPG 的状态语言 = **BGM 层报状态 + sfx 层 amb 报场景**(双层各司其职):
|
||||
|
||||
| 状态 | BGM 层 | sfx 层 amb | 听感设计 |
|
||||
|---|---|---|---|
|
||||
| 菜单(模态) | `bgm/menu` | amb 继续(音量不变) | "游戏还在,界面开了" |
|
||||
| 地图/探索 | `bgm/explore`(**恢复**,volume 0.35 轻垫) | `amb_<scene>` 主角 | 音乐是"底",环境音是"景" |
|
||||
| 村庄(安全区特例) | `bgm/village`(保留) | amb_village(bgm=0 时的垫底) | 温暖,与探索的紧张对比 |
|
||||
| 普通战斗 | `bgm/battle`(保留) | amb 停 | 进战斗 crossfade **400ms**(战斗要快切, urgency) |
|
||||
| Boss 战 | `bgm/boss`(保留) | amb 停 | 同上 400ms |
|
||||
| 战斗胜利 → 探索 | 关键过渡:`sfx/victory`(胜利标识音,见 11 文档 §5)→ battle/boss **淡出 1500ms** → `bgm/explore` **淡入 2000ms** + amb 恢复 | — | "从紧绷到松弛"是可听的,这是用户要的过渡 |
|
||||
| 战败 → 章首 | `bgm/battle` stopBgm(2000) → `voice/btl_lose` → village:bgm/village 淡入 1500ms | — | 重生即安全区音乐 |
|
||||
| 章结算/剧情(evt_ch*_end) | `bgm/ending`(保留) | amb 停 | 播完淡回 explore |
|
||||
|
||||
**裁定(修订 05-rpg-addendum §3)**:addendum 当时取消了 `bgm/explore`(探索期纯 amb);按用户本轮反馈恢复 explore 作为低音量状态垫乐(volume 0.35),amb 仍在 sfx 层不受影响。BGM 需求回到 5 首(village/explore/battle/boss/ending)+ menu。
|
||||
|
||||
## 8. 新 BGM 生产清单(Mureka prompt 草稿)
|
||||
|
||||
共性后缀:`", ambient pad, very sparse, no drums or minimal pulse, static harmony, calm, no vocals, seamless loop, 60-90 seconds"`。
|
||||
|
||||
| 资产 | prompt 草稿(英文) |
|
||||
|---|---|
|
||||
| storyline `bgm/menu` | "Dark post-apocalyptic menu pad, low warm drone with faint radio static texture, sibling mood to a dark ambient drone track" + 共性 |
|
||||
| escape `bgm/menu` | "Underground facility menu pad, soft low hum with distant water drip feel, slightly hopeful resolution tone" + 共性 |
|
||||
| simon `bgm/menu` | "Minimal memory-game menu pad, gentle mallet harmonics over soft sine pad, meditative, extremely light" + 共性 |
|
||||
| rhythm `bgm/menu` | "Electronic music-menu pad, slowed-down synthwave chords at 90 bpm feel, airy, between-songs breather" + 共性 |
|
||||
| space `bgm/menu` | "Space cockpit menu pad, soft engine-room hum with airy synth wash, weightless" + 共性 |
|
||||
| rpg `bgm/menu` | "Wuxia menu pad, single sustained guzheng harmonic over warm drone, ink-painting stillness" + 共性 |
|
||||
| rpg `bgm/explore` | "Wuxia exploration ambient music, sparse guzheng and dizi fragments over low forest drone, 60 bpm, mysterious calm, no vocals, seamless loop, sits quietly under ambience"(轻垫乐,混音时音量再降) |
|
||||
|
||||
## 9. 验收点
|
||||
|
||||
- 每游戏闭眼测试:菜单开/关、战斗进/出(RPG)仅靠 BGM 可辨。
|
||||
- `bgm=0.3`(小声)与 `bgm=0`(关闭)两档在各状态切换处不破音、不残响(引擎 crossfade 与增益总线叠加正确)。
|
||||
- menu pad 与主题曲同调性优先(storyline/escape/rpg 的 menu 与主题曲同 key;simon/space 无强约束)。
|
||||
@@ -0,0 +1,98 @@
|
||||
# 11 · 《剑与声》战斗重构规范(rpg battle rebalance)
|
||||
|
||||
> **给开发的实现要点摘要**
|
||||
> 1. 首战教学化:教学战从"学格挡+学攻击"扩为**四步强制分步**(认识指令→格挡→攻击→防御),教学战敌人 ATK 降为 2 且玩家 HP 锁底 1(不死)。§2。
|
||||
> 2. 新手难度保护:按**已完成战斗场数**分两档——第 1-3 场前摇 1.5s、敌方伤害 ×0.6;第 4-5 场过渡(1.25s、×0.8);第 6 场起恢复正常(1.0s、×1.0)。判定依据 `stats.battlesWon`,与等级无关(等级通过数值自然体现)。§3 数值表。
|
||||
> 3. 逃跑新手保护:Lv<3 逃跑 100% 成功;Lv≥3 普通战斗逃跑 70%,失败代价 = 敌方一个正常回合(有前摇、可格挡,不白打)。Boss/剧情战维持不可逃。§4。
|
||||
> 4. 战斗四状态声音标识:战斗开始 / 玩家回合 / 敌方前摇 / 胜利各有专属 sfx(新增 2 个:`turn_player`、`victory`)。§5。
|
||||
> 5. 现状衔接:现版(web/rpg/game.js)前摇固定 1.0s(+听风剑 0.3s)、逃跑 flee 布尔、教学战两步。本规范是**参数化 + 步骤扩展**,不改状态机骨架(05-rpg-chapter1 §3 的 10 状态转换表不变)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 现状问题(对应用户反馈)
|
||||
|
||||
- "第一次进战斗必须说明清楚交互方式":现教学战只有格挡(tut_b1/b2)+ 攻击(tut_b3)两步,**防御指令和指令切换本身没教**——玩家不知道左右滑能选招式、不知道有防御。
|
||||
- "战斗太难、要循序渐进":现版所有战斗前摇恒 1.0s、敌人满伤害,第一场正式战斗(enc_wolf)和 Boss 战用同一反应标准;逃跑非 Boss 必成但没有"失败"概念,缺少梯度。
|
||||
|
||||
## 2. 首战教学化(enc_teach_wolf 重排为四步)
|
||||
|
||||
教学战流水(teachStage 状态扩为 4 段,每段旁白引导 → 玩家亲手执行 → 确认后进下一段;每段 8s 无操作给一次重复提示,绝不卡死):
|
||||
|
||||
| 步 | stage | 旁白(新增语音 id,台词表见 §6) | 玩家动作 | 通过条件 |
|
||||
|---|---|---|---|---|
|
||||
| T0 | `menu` | `tut_b0`:"战斗里,左右滑选招式,单击出手。先试试,滑一滑。" | 左右滑 ≥2 次(听到指令名切换) | 切换 2 次 |
|
||||
| T1 | `attack` | `tut_b3`(现有):"轮到你了。左右滑选攻击,单击出剑。" | 选中攻击并单击 | 攻击命中一次 |
|
||||
| T2 | `parry` | `tut_b1`+`tut_b2`(现有):"它要扑了,听前摇!""就是现在,双击格挡!" | 前摇内双击 | 格挡成功或受击均可通过(受击掉血,教学点已到) |
|
||||
| T3 | `defend` | `tut_b6`(新增):"来不及格挡,就选防御。选防御,单击。" | 选中防御并单击 | 执行防御一次(敌方攻击减伤 50% 演示) |
|
||||
| T4 | — | `tut_b5`(现有):"好剑法!接下来,靠你自己了。" | 自由击杀 | 敌亡 |
|
||||
|
||||
- 教学战参数:teach_wolf **ATK 3→2**、HP 6 不变、前摇 **1.8s**(比正常宽 80%)、玩家 HP 锁底 1(不死,现版已有 clamp)、不可逃(现有)。
|
||||
- 顺序理由:先会"怎么选"(T0)再会"打"(T1)再会"保命"(T2/T3);格挡放在攻击后是让它成为"回合交换"的一部分而非孤立动作。
|
||||
|
||||
## 3. 难度曲线(新手保护分档)
|
||||
|
||||
保护档位由 `stats.battlesWon`(已完成战斗场数)决定,**每场战斗开始时取档**:
|
||||
|
||||
| 档 | battlesWon | 敌方前摇 | 敌方伤害系数 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| 教学 | 教学战 | 1.8s | ATK 2 特例 | §2 |
|
||||
| 保护 | 0-2(前 3 场) | **1.5s** | **×0.6**(向下取整,min 1) | 反应窗口宽 50%,掉血痛感低 |
|
||||
| 过渡 | 3-4(第 4-5 场) | 1.25s | ×0.8 | 渐回标准 |
|
||||
| 标准 | ≥5(第 6 场起) | 1.0s(听风剑 +0.3s) | ×1.0 | 现版数值 |
|
||||
|
||||
### 第一章遭遇战数值表(最终版,含推荐等级)
|
||||
|
||||
| 遭遇战 | 敌人 | HP | ATK(标准) | 前摇 | 经验/金币 | 推荐等级 | 说明 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| enc_teach_wolf | 教学野狼 | 6 | 2(教学特例) | 1.8s | 5 / 0 | Lv1 | 四步教学,锁血不死 |
|
||||
| enc_wolf | 野狼 | 10 | 4(保护档实际 2) | 按档位 | 8 / 5 | Lv1 | 可逃;保护档内打它=2 伤/刀 |
|
||||
| enc_bandits | 山贼 ×2 连战 | 16+16 | 6(过渡档实际 4) | 按档位 | 24 / 24 | Lv2 | 不可逃;连战不回血 |
|
||||
| enc_elite | 寨丁头目 | 24 | 8 | 标准 | 20 / 25 | Lv2-3 | 强攻线;半血有狠话 |
|
||||
| enc_sneak | 山贼+毒蛛 | 16+12 | 6/7 | 标准 | 24 / 20 | Lv2 | 绕行线;胜后进 Boss 前回满 |
|
||||
| enc_boss1 | 黑风寨主 | 45 | 10(半血 12) | 标准 | 50 / 100 | **Lv3** | 不可逃;进 Boss 战前强制提示(§4) |
|
||||
|
||||
等级节奏校验:教学狼 5 + 野狼 8 + 山贼 24 + 头目/偷袭 20-24 + 沿途 ≈ 60 exp 到 Boss 前 → Lv3(20+40=60 正好升 3)。Lv3 玩家(HP36、铁剑 atk12、皮甲 def2):保护档已过,Boss 10-2=8~11 伤/刀,可吃 4 刀;格挡成功 2-3 伤。会格挡=稳过,不格挡=紧过,符合"技巧有收益"原则。
|
||||
|
||||
**Boss 保护例外**:enc_boss1 始终标准档(battlesWon 再多也不再放宽;battlesWon 不足 5 时打 Boss 也不享受 1.5s 前摇——Boss 是毕业考)。实现:`enc.boss` 已存在,取档时 `boss ? 标准 : 按 battlesWon`。
|
||||
|
||||
## 4. 逃跑规则
|
||||
|
||||
| 玩家等级 | 普通战斗 | Boss/剧情战(flee:false) |
|
||||
|---|---|---|
|
||||
| Lv < 3 | **100% 成功**(新手保护) | 不可逃(btl_noflee) |
|
||||
| Lv ≥ 3 | 70% 成功;失败:播 `btl_flee_fail`(新增)→ 敌方直接进入正常前摇回合(**可格挡**,不白打) | 不可逃 |
|
||||
|
||||
实现:现版 `_fleeCheck` 是 flee 布尔直出;改为 `{ allowed, rate }`:`allowed=false` 播 btl_noflee;`rate = lv<3 ? 1.0 : 0.7`,失败走 ENEMY_TELEGRAPH。
|
||||
|
||||
**进 Boss 战提示**:首次进入 enc_boss1 且 Lv<3 时,门前插播 `boss1_warn`(新增):"里面就是黑风寨主。你现在回去练练再来,也来得及。"——给低等级玩家一个知情回头机会(gate 场景 back 选项本来就在)。
|
||||
|
||||
## 5. 战斗状态声音标识(听觉状态语言的战斗部分)
|
||||
|
||||
| 状态 | 声音标识 | 资产 |
|
||||
|---|---|---|
|
||||
| 战斗开始 | `bgm/battle` 400ms 切入(10 文档 §7)+ 现有 `btl_start_<enemy>` | 已有 |
|
||||
| **玩家回合开始** | 新增 `sfx/turn_player`:一声轻亮的剑鸣/木鱼短音("轮到你"的听觉标点,每回合都出现,必须极短 ≤0.4s、不烦) | **新增(程序合成即可,上行双音)** |
|
||||
| 敌方前摇 | 现有 `tel_<enemy>` + 窗口开启 `beat` 轻震(addendum §1) | 已有 |
|
||||
| **胜利** | 新增 `sfx/victory`:3 音上行短号角(≤1.2s),随后 BGM 过渡(10 文档 §7 的 1.5s 出/2s 入) | **新增(SA3:"triumphant short brass fanfare, 3 rising notes, wuxia style, under 1.5 seconds")** |
|
||||
| 战败 | 现有 `hurt` + `btl_lose` + battle BGM 2s 淡出 | 已有 |
|
||||
|
||||
`turn_player` 在每回合 PLAYER_SELECT 进入时播;教学战 T0 的"指令切换"教学正好以它为锚("听到这个声音,就是你的回合"——写进 `tut_b0` 台词)。
|
||||
|
||||
## 6. 新增语音(补录清单,×2 性别,交音频总监)
|
||||
|
||||
| id | 台词全文 | 用途 |
|
||||
|---|---|---|
|
||||
| `tut_b0` | 战斗里,左右滑选招式,单击出手。听到这个声音,就是你的回合。先滑一滑,试试。 | 教学 T0("这个声音"= turn_player,旁白落音后 0.5s 播 turn_player 示范) |
|
||||
| `tut_b6` | 来不及格挡,就选防御。左右滑,选防御,单击。 | 教学 T3 |
|
||||
| `btl_flee_fail` | 没甩掉!它追上来了。 | Lv≥3 逃跑失败 |
|
||||
| `boss1_warn` | 里面就是黑风寨主。你现在回去练练再来,也来得及。 | Lv<3 首次到 boss1 |
|
||||
|
||||
instruct 沿用 ch1 台词表常量(female=Serena / male=Uncle_Fu,讲武侠故事/说书人)。
|
||||
|
||||
## 7. 验收点
|
||||
|
||||
- 首战:不做任何正确操作也不死(锁底 1);四步每步都能被看门狗兜底推进。
|
||||
- 保护档实测:第 2 场战斗野狼每刀 ≤2 伤、前摇明显变慢(可听)。
|
||||
- Lv2 逃跑必成 ×10 次;Lv3 后逃跑出现失败且失败后可格挡。
|
||||
- Lv2 到 Boss 门前听到 `boss1_warn`;Lv3 到则不播。
|
||||
- `turn_player` 每回合出现且不与前摇音/指令语音叠放(回合切换处留 200ms 间隙)。
|
||||
@@ -0,0 +1,93 @@
|
||||
# 12 · 跳过旁白 + 长按加速 · 全局 UX 规范(含男女声边界核查)
|
||||
|
||||
> **给开发的实现要点摘要**
|
||||
> 1. 单击跳过当前句:§1 逐游戏裁定表——核心规则是"**voice 播放中单击=跳过本句;无 voice 时单击=原语义**",语音链衔接统一"跳下一句"(不是跳到节点末)。
|
||||
> 2. 长按加速(引擎临时 1.7× voice 语速):§2 豁免表——rhythm 演奏阶段全局豁免,其余游戏默认允许。引擎层拦截 longpress,游戏不收此手势。
|
||||
> 3. 首局提示时机:§3——不进语音资产,教学自然涵盖 + 大厅 footer 文案。
|
||||
> 4. §4 男女声边界核查结论:storyline/rpg 实际行为**符合**"只有旁白跟随设置、角色音固定",无需修复;两处命名/计数勘误。
|
||||
|
||||
---
|
||||
|
||||
## 1. 单击跳过当前句
|
||||
|
||||
### 1.1 总则
|
||||
|
||||
- **语境判定**:`voice` 层有音频在播时,单击 = 跳过当前句(`stopVoice()` 截断当前句,链播自然进下一句——引擎语义"被打断不触发 onComplete",因此**实现上不是 stopVoice 而是"截断当前句但保住链"**:需引擎或游戏层支持 `skipVoice()`(截断当前句并触发 onComplete 续链)。若引擎暂无此 API,游戏层用等价实现:手动推进链。以引擎最终提供的 API 为准)。
|
||||
- **无 voice 时单击 = 各游戏原语义**(检查/确认/继续),两态有明确的听觉区分(有语音在播 vs 没有),不混淆。
|
||||
- **跳到节点末 vs 跳下一句**:统一**跳下一句**。跳到节点末会让玩家误过后续信息且实现要感知"节点"边界;"逐句跳"心智最简单:不想听就多点几下。
|
||||
- 跳过不给震动(跳过是浏览操作不是确认;双击=重听的对偶操作,保持安静)。
|
||||
|
||||
### 1.2 逐游戏裁定表
|
||||
|
||||
| 游戏 | 阶段 | 单击=跳过本句? | 说明 |
|
||||
|---|---|---|---|
|
||||
| storyline | 剧情对白 | ✅ 可跳 | 节点最后一句被跳 = 进下一节点(现有"单击继续"语义自然延伸) |
|
||||
| storyline | 抉择提示(prompt) | ❌ 不可跳 | 左右滑抉择前的选项说明必须听完(盲玩公平性) |
|
||||
| escape | 引导 G0-G7 | ❌ 不可跳(下滑=跳整个引导,已有) | 引导句即操作指令,跳句会破坏步骤机 |
|
||||
| escape | PLAY 检查描述/卡关提示/背包 | ✅ 可跳 | 熟练玩家快速刷检查 |
|
||||
| escape | 关键获得(found_key/unlock_cabinet/fix_box/escape) | ❌ 不可跳 | 谜题链进展的叙事回报,总长 <10s |
|
||||
| simon | 教学 T0-T7 | ❌ 不可跳(下滑=跳教学,已有) | 同 escape 引导 |
|
||||
| simon | 轮次播报 round_*、成绩播报 | ✅ 可跳 | 高轮次玩家最需要 |
|
||||
| simon | input 阶段 | — 无语音 | 无冲突 |
|
||||
| rhythm | intro/tut/结算/选曲 | ✅ 可跳 | 演奏阶段(main)无语音,无冲突 |
|
||||
| rhythm | mid_song | ❌ 不可跳(仅 2s,不值得跳) | 演奏中,手势是演奏输入 |
|
||||
| space | 演练 D0-D5 | ❌ 不可跳(下滑=跳演练,已有) | 教学即玩法 |
|
||||
| space | feat_boost/feat_shield 引入句 | ✅ 可跳 | 二周目熟练玩家 |
|
||||
| space | 归因/保护期/结算播报 | ✅ 可跳 | |
|
||||
| rpg | 场景 desc、NPC 对白、事件句 | ✅ 可跳 | 刷图玩家核心诉求 |
|
||||
| rpg | 战斗指令名 cmd_*、教学战 tut_b* | ❌ 不可跳 | 指令名 <1s 且正在选指令,跳过会打乱选择节奏;教学句同引导逻辑 |
|
||||
| rpg | 状态播报链(st_*) | ✅ 可跳 | 逐句跳过即"快进状态查询" |
|
||||
|
||||
### 1.3 与"单击 300ms 延迟"的相容性
|
||||
|
||||
跳过是非即时操作,300ms 延迟无影响。注意双击=重听与单击=跳过的对偶关系:引擎的双击窗口保证两者不误判(现有机制天然支持)。
|
||||
|
||||
## 2. 长按加速(引擎:按住 = voice 层临时 1.7×)
|
||||
|
||||
**核查注记**:本规范按用户声明的既定事实("引擎已实现长按=临时 1.7 倍速")撰写;当前 `web/engine/gesture.js` 输出仍为 6 手势、未见 longpress 实现——若引擎接口与本节假设不同,**以引擎实际 API 为准**,游戏侧豁免规则不变。
|
||||
|
||||
### 2.1 总则
|
||||
|
||||
- 长按由**引擎层拦截**:按住 ≥400ms 未位移 → 当前 voice 句 playbackRate 临时 1.7(松手或句终恢复 settings.speed),**不产生手势回调**(游戏永远收不到 longpress)。BGM/sfx 不受影响。
|
||||
- 与设置语速的关系:长按倍率 = max(1.7, 当前 settings.speed) 之上的"再快一档"语义——settings.speed=1.7 时长按无效果(已是特快)。
|
||||
- 加速中的 onComplete 时序自然提前(句长缩短),语音链不断。
|
||||
|
||||
### 2.2 豁免表
|
||||
|
||||
| 游戏 | 豁免 | 理由 |
|
||||
|---|---|---|
|
||||
| rhythm | **main(演奏)+ tut(教学跟打)阶段全局豁免**(游戏向引擎注册关闭 rate boost) | 演奏中手指可能长按屏幕边缘蓄力;且 mid_song 加速会破坏"语音提示与节拍网格对齐"的幻觉。教学跟打同理 |
|
||||
| rhythm | select/end/菜单正常允许 | 结算播报快进是刚需 |
|
||||
| simon | playback(序列播放)阶段豁免 | 序列是记忆对象,虽然 tone 是 sfx 不受 rate 影响,但该阶段无 voice,豁免无成本;input/announce/结算允许 |
|
||||
| space | playing 阶段豁免 | 对局中无长语音(归因句 2-3s),豁免避免长按与连续滑动的手势边界模糊;演练/结算允许 |
|
||||
| escape / storyline / rpg | 不豁免(全局允许) | 叙事类游戏正是长按加速的主战场 |
|
||||
| RPG 战斗 | 允许但有边界:敌方前摇是 **sfx**(tel_*)不受 rate 影响,格挡窗口时长不变——加速 voice 不影响战斗判定,安全 | 裁定:允许 |
|
||||
|
||||
豁免实现:游戏在阶段切换时调引擎开关(如 `audio.setRateBoostEnabled(false)`,以引擎实际 API 为准);默认开启。
|
||||
|
||||
## 3. 首局提示时机(两个功能的发现性)
|
||||
|
||||
原则:**不新增语音资产、不打断首局沉浸**。
|
||||
|
||||
1. **大厅 footer 文案**(可视化,零成本):footer 已有"单击判定有约 300ms 延迟"一行,追加一行:"播放旁白时:单击=跳过本句,按住=加速播放"。
|
||||
2. **各游戏教学内自然涵盖**:
|
||||
- 有交互教学的游戏(simon/space/rhythm/rpg/escape)教学本身已教六手势;跳过/长按是**增强功能而非必需操作**,不教——玩家从大厅文案或摸索中发现即可(发现成本低:单击本来就常用)。
|
||||
- storyline(无教学)在首个抉择点 prompt 播完后追加一次现有系统提示?——**不加**。storyline 的"单击继续"已是事实上的跳过来由,长按从大厅文案发现。
|
||||
3. 若后续数据显示玩家长语音中途退出率高,再考虑在第二局长语音加一次性提示句(届时补录 `sys_skip_hint`,本规范预留 id)。
|
||||
|
||||
## 4. 附:男女声设置边界核查(用户反馈"可选男女声只是旁白,不是游戏内容")
|
||||
|
||||
核查方法:读 `web/storyline/game.js`、`web/rpg/game.js` 实际播放路径 + 资产目录结构 + `tools/gen_voice_dual.py` 台词表归属。
|
||||
|
||||
### 结论:符合规范,无需修复
|
||||
|
||||
| 检查项 | storyline | rpg |
|
||||
|---|---|---|
|
||||
| 旁白/系统音在 `voice/<gender>/` 双目录 | ✅ 36 id 双性别 | ✅ 旁白 id 双性别 |
|
||||
| 角色/NPC 音平铺 `voice/`(固定音色,引擎平铺回退命中) | ✅ n02_linwan(Serena)、n07_dog(Dylan)、e1_child/n03_msg/n05_bcast(Vivian) 均只存在于平铺 | ✅ npc_* 14 id 只存在于平铺,female/male 目录均无 npc_ 文件 |
|
||||
| 角色音被错误切性别的路径 | **未发现** | **未发现** |
|
||||
|
||||
### 两处勘误(非 bug)
|
||||
|
||||
1. **storyline `n11_child` 命名误导**:该 id 在两个性别目录都存在,初看像角色"小满"被切性别——实际它是**旁白句**(`gen_voice_dual.py:95`,speaker 组 `_SL_NARR`,文本是旁白叙述中嵌入小满的话)。行为正确,但文件名易误读;**维持不改**(改 id 要动代码+资产两端,无实际收益),此处留档说明。
|
||||
2. **RPG NPC 台词计数勘误**:05-rpg-ch1-voice-ids.md 表头写"NPC 16 句",实际表内 14 id(村长 4 + 猎人 4 + 头目 3 + 寨主 3)。以 14 为准,音频资产已按 14 落盘,文档表头笔误不另改文件,记于此。
|
||||
@@ -0,0 +1,110 @@
|
||||
# 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 豁免)。
|
||||
+52
-12
@@ -15,9 +15,10 @@ web/
|
||||
│ ├── gesture.js # 6 手势识别(触摸+鼠标,内置基础震动反馈)
|
||||
│ ├── audio.js # Web Audio 三层音频引擎 + 启动遮罩(自动应用用户设置)
|
||||
│ ├── settings.js # 全局用户设置(voice/speed/bgm,localStorage 持久化)
|
||||
│ ├── haptics.js # navigator.vibrate 震动封装(预定义震型)
|
||||
│ ├── haptics.js # navigator.vibrate 震动封装(预定义震型 + iOS 视觉降级)
|
||||
│ ├── game.js # Game / StateMachineGame 基类
|
||||
│ └── style.css # 全屏黑底 + 封面铺满 + 屏蔽系统手势
|
||||
│ ├── style.css # 全屏黑底 + 封面铺满 + 屏蔽系统手势 + 闪光降级样式
|
||||
│ └── vendor/soundtouch.js # SoundTouch 0.3.0(voice 变速不变调,LGPL v2.1)
|
||||
├── server/ # 用户系统服务器(静态托管 + 注册/登录/进度 API)
|
||||
│ ├── server.js
|
||||
│ └── README.md # API 文档
|
||||
@@ -92,7 +93,8 @@ cp -r web/template web/<name>
|
||||
iOS Safari 和 Chrome 都要求 AudioContext 必须在一次真实用户手势中创建/恢复。
|
||||
引擎用启动遮罩解决:
|
||||
|
||||
1. 页面加载后 `showStartOverlay()` 显示全屏封面 + "轻触开始"(呼吸动画);
|
||||
1. 页面加载后 `showStartOverlay()` 显示全屏封面 + "轻触开始"(呼吸动画,
|
||||
提示文字位于屏幕 30% 高度处,避开封面图底部文字区);
|
||||
2. 用户第一次点按遮罩 → 引擎在手势回调里 `new AudioContext()` + `resume()`;
|
||||
3. 遮罩移除,Promise resolve → 你调 `game.start()` 接管。
|
||||
|
||||
@@ -130,6 +132,10 @@ new WebAudioEngine(basePath = 'audio/', opts?)
|
||||
(与 Android 差异:Web 端**不需要**音量 0 假播预热,解码缓存即可。)
|
||||
- `stopBgm(fadeOutMs = 800)` — 淡出后释放 BGM。
|
||||
- `stopVoice()` — 打断当前对白并清空排队,不触发 onComplete,BGM 恢复。
|
||||
- `skipVoice()` — **跳过当前对白但让语音链继续**:停掉当前 voice 并视为
|
||||
这句自然播完——触发其 onComplete(游戏层的链播靠它推进)并继续等待队列。
|
||||
与 stopVoice 的差异:stopVoice 作废整条链,skipVoice 只跳当前句。
|
||||
游戏层自行绑定手势(如长按/特定滑动的"跳过这句")。
|
||||
- `stopAll()` — stopBgm(200) + stopVoice()(sfx 很短,不主动停)。
|
||||
|
||||
三层行为(对齐 Android DefaultAudioEngine):
|
||||
@@ -137,8 +143,31 @@ new WebAudioEngine(basePath = 'audio/', opts?)
|
||||
| 层 | 播放器 | 特性 |
|
||||
|---|---|---|
|
||||
| BGM | AudioBufferSourceNode(双实例轮换) | 循环;切换时新源 0→满、旧源 →0 交叉淡入,淡出后 stop |
|
||||
| voice | 单通道 | duck BGM 到 20%(300ms 渐降),播完 300ms 恢复;onComplete 驱动链播 |
|
||||
| sfx | AudioBufferSourceNode 即发即弃 | 预解码 AudioBuffer 缓存,低延迟,可叠加 |
|
||||
| voice | SoundTouch 时间拉伸管线(见下) | duck BGM 到 20%(300ms 渐降),播完 300ms 恢复;onComplete 驱动链播 |
|
||||
| sfx | AudioBufferSourceNode 即发即弃 | 预解码 AudioBuffer 缓存,低延迟,可叠加;总线基础增益 0.8 |
|
||||
|
||||
**爆音防护**:master 链末端挂 `DynamicsCompressorNode` 限幅
|
||||
(threshold -6dB / ratio 12 / attack 3ms / release 250ms),sfx 总线基础
|
||||
增益 0.8。BGM+voice+多个 sfx 并发叠加超过 0dBFS 时由限幅器压限,
|
||||
不再在 destination 硬削波(爆音/突然最大音量的根治)。
|
||||
|
||||
**voice 变速不变调(SoundTouch 管线)**:voice 层播放走
|
||||
`vendor/soundtouch.js`(SoundTouch 0.3.0,LGPL v2.1,ScriptProcessorNode
|
||||
实现):`WebAudioBufferSource → SimpleFilter(SoundTouch tempo) →
|
||||
ScriptProcessorNode → gain → voiceBus`。`settings.speed` 只改 tempo 不改
|
||||
pitch,1.0/1.35/1.7 均不变调;自然结束由"源消耗位置 ÷ tempo"定时器判定,
|
||||
onComplete/打断/排队语义与旧 BufferSource 实现完全一致。注意 voice 有
|
||||
~100ms 处理延迟(对白场景无感),且 ScriptProcessorNode 已废弃但全平台
|
||||
(含 iOS Safari)可用。
|
||||
|
||||
**长按快进(游戏零改动)**:voice 播放中长按屏幕 → 旁白临时 1.7 倍速
|
||||
(不变调),松开恢复 `settings.speed`。由 gesture.js 派发的 window 事件
|
||||
(`soundgame:longpress` / `soundgame:longpressend`)驱动,audio.js 内置监听。
|
||||
|
||||
**状态 BGM 约定**:游戏按状态(菜单/探索/战斗/结算)直接
|
||||
`play('bgm/xxx')` 切换即可——引擎 crossfade 已够用;`settings.bgm=0` 时
|
||||
切换只更新"想播"不加载不播放,用户重新打开 BGM 时自动补播最后一个状态
|
||||
BGM。游戏层无需为此写任何判断。
|
||||
|
||||
**用户设置自动生效(settings.js,游戏代码无需改动):**
|
||||
|
||||
@@ -146,9 +175,9 @@ new WebAudioEngine(basePath = 'audio/', opts?)
|
||||
`play('voice/intro')` 依次尝试 `audio/voice/<gender>/intro.{ogg,m4a,mp3,wav}`,
|
||||
全部找不到再回退平铺的 `audio/voice/intro.*`(过渡期资产未分性别也能播)。
|
||||
缓存键含性别,游戏中途切换音色下一句即用新性别资产。
|
||||
- `settings.speed`(`1.0|1.35|1.7`,默认 `1.0`):voice 层
|
||||
`source.playbackRate`,在创建 source 时读取,**从下一句生效**
|
||||
(进行中的句子不变速)。
|
||||
- `settings.speed`(`1.0|1.35|1.7`,默认 `1.0`):voice 层 SoundTouch
|
||||
tempo(**不变调**),在创建播放实例时读取,**从下一句生效**
|
||||
(进行中的句子不变速——除非长按快进,见上)。
|
||||
- `settings.bgm`(`1.0|0.3|0`,默认 `1.0`):BGM 层独立增益总线。
|
||||
改动对**进行中的 BGM 立即生效**(150ms 渐变);调到 `0` 立即淡出停止
|
||||
且此后 `play('bgm/...')` 只记意图不加载不播放;从 `0` 调回非零时,
|
||||
@@ -195,7 +224,11 @@ vibrate('error'); // 预定义名称
|
||||
vibrate([50, 30, 50]); // 自定义震型
|
||||
```
|
||||
|
||||
- 特性检测 `'vibrate' in navigator`;不支持的平台(iOS Safari)**静默 no-op**。
|
||||
- **视觉降级(iOS 等无 vibrate 平台)**:`hapticsSupported === false` 时
|
||||
`vibrate()` 自动改为全屏边框闪光(`#haptics-flash` 覆盖层,样式在
|
||||
style.css):震型 → 颜色/闪烁次数(confirm 白×1 / error 红×2 /
|
||||
success 绿×1 / warning 橙×3 / heartbeat 粉×2 / pickup 青×1 / hit 强红×1 /
|
||||
danger 红×3 快 / swipe、beat 极淡白×1)。游戏代码无需判断平台。
|
||||
- gesture.js 已内置基础反馈:滑动→`swipe`,tap→`confirm`,doubletap→`confirm`。
|
||||
**游戏逻辑层只需在语义事件(error/success/warning/heartbeat 等)处自行调用**,
|
||||
不要对手势本身重复调 `vibrate('confirm')`/`vibrate('swipe')`,否则会双重震动。
|
||||
@@ -204,7 +237,8 @@ vibrate([50, 30, 50]); // 自定义震型
|
||||
|
||||
```js
|
||||
const detach = attachGestures(element, onGesture, config?)
|
||||
// onGesture: (g: 'up'|'down'|'left'|'right'|'tap'|'doubletap') => void
|
||||
// onGesture: (g: 'up'|'down'|'left'|'right'|'tap'|'doubletap'
|
||||
// |'longpress'|'longpressend') => void
|
||||
// detach(): 解除绑定
|
||||
```
|
||||
|
||||
@@ -216,6 +250,7 @@ const detach = attachGestures(element, onGesture, config?)
|
||||
| `swipeMinVelocity` | 400 px/s | 平均速度阈值(位移 / 拖动时长) |
|
||||
| `doubleTapWindow` | 300 ms | 双击判定窗口 |
|
||||
| `tapSlop` | 24 px | 位移小于此才算点按 |
|
||||
| `longpressMs` | 450 ms | 按住不动超过此值触发 `longpress` |
|
||||
|
||||
- 方向取位移较大的轴,斜滑归一到最近主轴(防斜滑误判)。
|
||||
- 触摸 + 鼠标双支持(桌面可用鼠标拖拽/点击调试);多指触摸忽略。
|
||||
@@ -224,8 +259,13 @@ const detach = attachGestures(element, onGesture, config?)
|
||||
(`style.css` 的 `#game-root` 已带)。
|
||||
- 手势绑定是全屏捕获层级的:绑在 `#game-root` 上即可覆盖整个屏幕。
|
||||
- **内置基础震动反馈**(haptics.js):滑动识别成功→`swipe`、tap→`confirm`、
|
||||
doubletap→`confirm`;不支持震动的平台自动静默。游戏语义反馈
|
||||
(error/success/warning 等)由游戏层调用 `vibrate()`。
|
||||
doubletap→`confirm`;不支持震动的平台自动走视觉降级(边框闪光)。
|
||||
游戏语义反馈(error/success/warning 等)由游戏层调用 `vibrate()`。
|
||||
- **长按**:按住不动 ≥450ms 触发 `'longpress'`,松开触发 `'longpressend'`;
|
||||
长按期间不触发 tap;位移超 tapSlop 取消(已激活则先补发 `longpressend`,
|
||||
滑动照常判定)。长按同时派发 window 事件 `soundgame:longpress(end)`——
|
||||
audio.js 内置监听实现"长按=旁白临时 1.7 倍速(不变调)"。
|
||||
**游戏若把 longpress 挪作他用,注意语音快进行为会同时发生。**
|
||||
|
||||
**单击有约 300ms 延迟**:引擎要等双击窗口关闭才能确定是单击,`tap`
|
||||
回调因此延迟 ~300ms 触发(`doubletap` 和滑动是即时的)。这是引擎级行为,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user