初始提交:3 款纯音频游戏 + 共享引擎 + 完整文档与资产管线
- 共享引擎(app/src/main):GestureEngine 6 手势识别、AudioEngine 三层音频 (ExoPlayer BGM 交叉淡入 / 对白 ducking / SoundPool 低延迟)、Game/GameEngine 状态机接口、MainActivity 全屏封面 + TalkBack - 《声命线》storyline:末世互动广播剧,3 幕 8 抉择点 4 结局 - 《声东击西》reflex:听声辨位反应,12 波战斗 + BGM 三档 BPM 变速 - 《暗室》escape:3x3 网格密室逃脱,钥匙→铁柜→保险丝→电箱→大门谜题链 - 文档:setup(从零搭建)/ architecture(架构)/ engine-api(引擎 API)/ asset-pipeline(资产流水线)/ games/*(三款游戏设计文档) - 资产管线:Qwen3-TTS 对白 + 程序合成音效/BGM + Mureka BGM 的 gen 脚本与台账, 全部 ogg 资产入库可复现 - env.d 环境脚本:android/tts 入库;sfx/mureka 含密钥不入库,仅提交 .example.sh 模板
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# 《声东击西》(reflex) — 听声辨位反应 设计文档
|
||||
|
||||
- 包名:`com.soundgame.reflex`
|
||||
- 代码:`app/src/reflex/java/com/soundgame/game/GameFactory.kt`
|
||||
(`ReflexGame` 与 `GameFactory` 同文件,与其他两款游戏的拆文件风格不同)
|
||||
- 生成脚本:`app/src/reflex/gen/`(`gen_voice.py` / `gen_sfx_bgm.py` /
|
||||
`convert_audio.py` / `fix_num6.py`)
|
||||
|
||||
敌人从四个方向来袭,玩家纯靠听声音方位做出对应手势。教学演练 → 12 波战斗
|
||||
(节奏递增、BGM 三档变速)→ 结算播报得分。共 5 点血,血尽或通关进结算。
|
||||
|
||||
## 方位声音设计(gen_sfx_bgm.py)
|
||||
|
||||
| 方位 | 提示音 | 声学设计 | 应对手势 |
|
||||
|---|---|---|---|
|
||||
| 左 | cue_left | 0.45s 噪声扫频 whoosh,声像硬打左声道 | 左滑 |
|
||||
| 右 | cue_right | 同上,硬打右声道 | 右滑 |
|
||||
| 上 | cue_up | 高音上行琶音 E6-G6-B6(1319/1568/1976 Hz) | 上滑 |
|
||||
| 下 | cue_down | 低音下行轰击 110→55Hz + 闷响 | 下滑 |
|
||||
| 正面 | warn_front | 急促三响警报(880/660 交替,约 1.0s) | 单击格挡 |
|
||||
|
||||
正面警报特意做到 ~1s 且反应窗口强制 ≥ 1100ms(`FRONT_MIN_WINDOW_MS`),
|
||||
用来覆盖单击因双击判定窗口产生的 ~300ms 回调延迟(见 docs/architecture.md)。
|
||||
|
||||
## 手势映射
|
||||
|
||||
| 手势 | INTRO | PRACTICE | BATTLE | ENDED |
|
||||
|---|---|---|---|---|
|
||||
| 四向滑动 | 忽略 | 对应方向则过,错则重播提示 | 击杀对应方向敌人;划错断连击不扣血 | 忽略 |
|
||||
| 单击 | 忽略 | 正面演练格挡 | 格挡正面攻击;无正面攻击不惩罚 | 重开(跳过教学) |
|
||||
| 双击 | 忽略 | 忽略 | 音爆冲击清屏(12s 冷却) | 忽略 |
|
||||
|
||||
教学旁白(INTRO)期间完全不响应手势,防连点。
|
||||
|
||||
## 波次表(waveCfg,共 12 波)
|
||||
|
||||
| 波次 w | 出怪数 4+w | 出怪间隔 ms | 反应窗口 ms | 正面概率 | BGM 档 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 5 | 2000 | 1700 | 7.3% | calm (100 BPM) |
|
||||
| 2 | 6 | 1873 | 1614 | 8.6% | calm |
|
||||
| 3 | 7 | 1746 | 1528 | 9.9% | calm |
|
||||
| 4 | 8 | 1619 | 1442 | 11.2% | **tense (128 BPM)** + 语音播报 |
|
||||
| 5 | 9 | 1492 | 1356 | 12.5% | tense |
|
||||
| 6 | 10 | 1365 | 1270 | 13.8% | tense |
|
||||
| 7 | 11 | 1238 | 1184 | 15.1% | tense + 语音播报 |
|
||||
| 8 | 12 | 1111 | 1098 | 16.4% | tense |
|
||||
| 9 | 13 | 984 | 1012 | 17.7% | **frantic (152 BPM)** |
|
||||
| 10 | 14 | 857 | 926 | 19.0% | frantic + 语音播报 |
|
||||
| 11 | 15 | 730 | 840 | 20.3% | frantic |
|
||||
| 12 | 16 | 600(触底) | 750(触底) | 21.6% | frantic + 总攻语音 |
|
||||
|
||||
- 出怪间隔公式:`(2000 - (w-1)*127).coerceAtLeast(600)`
|
||||
- 反应窗口公式:`(1700 - (w-1)*86).coerceAtLeast(750)`;正面攻击取
|
||||
`max(窗口, 1100)`
|
||||
- 正面概率公式:`0.06 + w*0.013`
|
||||
- 每波首怪在波开始后 1400ms 出现;波间间隔 1800ms
|
||||
|
||||
## 计分与状态
|
||||
|
||||
- 击杀:`100 + 10 × 当前连击`;技能击杀固定 50/个;连击 5/10/15(每5) 有音效,
|
||||
连击 10 追加战友语音夸奖。
|
||||
- 漏怪:扣 1 血、断连击;HP=2 / HP=1 时各播报一次警告语音。
|
||||
- 双击技能:清空全部在场敌人,冷却 12s,冷却完成有语音提醒,冷却中双击
|
||||
播 `skill_denied`。
|
||||
- 结算:逐位播报得分(num_0..num_9 数字语音拼接),破纪录播 `new_record`,
|
||||
否则播报历史最高。**最高分为进程内变量,杀进程即丢。**
|
||||
- 时间调度全部走主线程 `Handler`(手势回调也在主线程),无需加锁;
|
||||
`onStop` 清空全部回调。
|
||||
|
||||
## 角色音色分配(gen_voice.py)
|
||||
|
||||
| 角色 | speaker | instruct | 负责内容 |
|
||||
|---|---|---|---|
|
||||
| 教官/旁白 | Uncle_Fu(低沉醇厚中年男声) | 战场教官语气(教学一字一句、战前激昂、重伤焦急等逐条指定) | 教学 tut_01-07、战报 wave_04/07/10/12、血量警告、胜负播报、报分、数字 0-9 |
|
||||
| 战友 | Vivian(明亮略带锋芒年轻女声) | 兴奋赞叹/轻快提醒/惊喜欢呼 | combo_praise、skill_ready、new_record、restart_hint、replay |
|
||||
|
||||
## 资产清单
|
||||
|
||||
| 层 | 数量 | 内容 |
|
||||
|---|---|---|
|
||||
| voice | 33 | 教学 7 + 战报 4 + 血量 2 + 激励 3 + 胜负/报分 6 + 重开 1 + 数字 10 |
|
||||
| sfx | 18 | 方位 cue 5(cue_left/right/up/down + warn_front)+ 反馈 5(hit/block/hurt/skill/skill_denied)+ 连击 3 + wave_horn + ui_start + warmup + victory_fanfare + gameover_sting |
|
||||
| bgm | 3 | bgm_calm / bgm_tense / bgm_frantic(程序合成脉冲节奏,100/128/152 BPM 各 8 小节,无缝循环) |
|
||||
|
||||
BGM 保留程序合成是有意为之:玩法要求三档 BPM 随波次精确切换,AI 生成曲目
|
||||
BPM 不精确会破坏节奏机制(见 README 待办与 mureka_log.md)。
|
||||
|
||||
## 已知缺陷 / 遗留线索
|
||||
|
||||
- **`fix_num6.py`**:数字"六"的 TTS 生成不稳(单次生成时长经常超界),
|
||||
单独写了个重试脚本(最多 4 次,取 0.3s~1.5s 的一条)。重新批量生成
|
||||
`gen_voice.py` 时 num_6 可能再次翻车,需重跑 fix 脚本。
|
||||
- **`warmup.wav` 是假资产**:0.1s 近静音文件(+1e-4 绕过峰值校验),
|
||||
只为 SoundPool 预热存在。
|
||||
- **最高分不持久化**:`highScore` 是 companion object 的 var,进程内有效。
|
||||
- 划错方向只断连击不扣血、无正面攻击时单击不惩罚——为掩盖单击延迟的
|
||||
有意宽容设计,严格模式下可视为难度漏洞。
|
||||
- 结算逐位报分在长分数时较拖沓(每位一条独立语音文件)。
|
||||
|
||||
## 调参入口
|
||||
|
||||
| 位置 | 参数 | 控制什么 |
|
||||
|---|---|---|
|
||||
| `ReflexGame` companion | `MAX_HP=5` / `TOTAL_WAVES=12` / `SKILL_COOLDOWN_MS=12000` / `FRONT_MIN_WINDOW_MS=1100` | 血量/波数/技能冷却/正面窗口下限 |
|
||||
| `waveCfg()` | attacks/interval/reaction/frontProb 四个公式 | 难度曲线核心 |
|
||||
| `startWave()` | BGM 切换阈值(w≥4 / w≥9)、语音播报波次 | 节奏与叙事节拍 |
|
||||
| `kill()` | 100/50 基础分、连击加成 10×combo | 计分 |
|
||||
| `gen_sfx_bgm.py` | cue 音频率/声像、`make_pulse_bgm(bpm, bars)` | 方位可辨度、BGM 速度与密度 |
|
||||
| `convert_audio.py` | voice 峰值归一 0.6、`-q:a 4/4/3` | 响度与体积 |
|
||||
Reference in New Issue
Block a user