Files
SoundGame/docs/design/05-rpg-chapter1.md
T
SoundGame Dev cc0f8c008d HTML5 重写:6 款游戏 + 用户系统 + 全局设置 + 5 轮迭代重构
- 新增 web/ 纯音频 HTML5 平台:共享引擎(手势/WebAudio 三层/设置/震动)、
  Node 零依赖服务器(静态 + 注册登录 + 进度存档 API)
- 游戏:剑与声(RPG 新作)、声命线、暗室(重设计)、音序回响(重设计)、
  节拍行者(跟随领奏重构)、盲航(同向闪避重构);声东击西删除
- 全局功能:男声/女声双套 TTS 资产、三档语速、BGM 音量三档、
  震动反馈语言(10 种震型)、服务器进度同步
- 资产:899 ogg + 899 m4a(Qwen3-TTS 双性别语音、Stable Audio 3 音效、
  Mureka BGM 4+3 首),终检零缺失
- 文档:docs/design/ 13 篇设计审查文档、docs/audio/ 资产管线、
  web/server/README.md API 文档
2026-08-29 21:55:44 +08:00

239 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 05a · 《剑与声》第一章施工稿(rpg chapter 1,R4 资产 / R5 开发依据)
> **给开发者的实现要点摘要**
> 1. 本文件 + [05-rpg-ch1-voice-ids.md](05-rpg-ch1-voice-ids.md)(台词表)+ [05-rpg.md](05-rpg.md)(总设计)三者齐全即可施工。场景图、战斗状态机、数值表、存档结构全部定死,不允许实现时自由发挥。
> 2. 战斗是**定时器驱动的回合状态机**(§3 状态转换表):敌方前摇 1.0s 内双击=格挡(双击即时回调,规避 tap 延迟);指令循环 攻击→技能→防御→道具。
> 3. 第一章 8 场景、5 场固定遭遇战(明雷)、2 件装备 + 道具在商店/宝箱/支线获取(§5)。
> 4. 存档 data 结构 §6(含大厅卡片要显示的 `summary` 字符串);保存时机:场景切换/战斗结束/商店交易后。
> 5. 资产清单 §7:5 首 BGM(Mureka prompt 草稿)+ 35 个 sfx(Stable Audio 3 prompt 草稿 / 程序合成标注)。语音 ~114 句见台词表文件。
---
## 1. 第一章场景图(数据表,直接转 JSON)
```js
const CH1 = {
start: 'village',
scenes: {
village: { name: '雾口村', amb: 'amb_village', options: ['go_path', 'shop', 'rest', 'status'] },
path: { name: '林间小路', amb: 'amb_path', options: ['go_fork', 'investigate', 'back'] },
fork: { name: '岔路口', amb: 'amb_fork', options: ['go_chest', 'go_stream', 'back'] },
chest: { name: '枯树洞', amb: 'amb_chest', options: ['open_chest', 'back'] },
stream: { name: '溪流', amb: 'amb_stream', options: ['drink', 'go_hunter', 'back'],
encounter: 'enc_teach_wolf' }, // 首次进入先触发教学战
hunter: { name: '猎人小屋', amb: 'amb_hunter', options: ['talk_hunter', 'go_deepwood', 'back'] },
deepwood: { name: '密林深处', amb: 'amb_deepwood', options: ['go_gate', 'back'],
encounter: 'enc_bandits' }, // 首次进入触发山贼连战
gate: { name: '黑风寨门前', amb: 'amb_gate', options: ['assault', 'sneak', 'back'] },
boss1: { name: '聚义厅', amb: 'amb_hall', options: [],
encounter: 'enc_boss1' }, // 由 gate 两个选项分别进入
},
};
```
选项语义(选项 id → 行为):
| 选项 id | 播报语音 | 行为 |
|---|---|---|
| `go_*` | `opt_go_<场景>` | 切换场景(播脚步 sfx + 新场景 desc) |
| `back` | `opt_back` | 回上一场景 |
| `shop` | `opt_shop` | 进商店子菜单(§4) |
| `rest` | `opt_rest` | HP/MP 回满,播 `sys_rest`;仅 village |
| `status` | `opt_status` | 角色状态播报(同上滑) |
| `investigate` | `opt_investigate` | 一次性:+15 金币(flag `chest_path`),播 `evt_gold15`;之后播 `evt_nothing` |
| `go_chest` | `opt_go_chest` | 岔路左支线 |
| `open_chest` | `opt_open_chest` | 一次性:金疮药×2(flag `chest_fork`) |
| `drink` | `opt_drink` | HP 回满,播 `sys_drink` |
| `talk_hunter` | `opt_talk_hunter` | 支线对话(flag `hunter_quest`:金疮药×1 + 商店九折 flag `shop_discount`) |
| `assault` | `opt_assault` | 战 `enc_elite` → 胜后进 boss1 |
| `sneak` | `opt_sneak` | 战 `enc_sneak`(较弱)→ 进 boss1 且 HP/MP 回满 |
## 2. 遭遇战表(第一章,全部明雷固定)
| 遭遇 id | 敌人 | 触发 | 特殊 |
|---|---|---|---|
| `enc_teach_wolf` | 教学野狼 ×1 | stream 首次进入 | 教学战:玩家 HP 锁底 1(不败),分步教学(台词表 B 组) |
| `enc_wolf` | 野狼 ×1 | 教学战后 stream 再入 50% 刷新一次 | 可逃 |
| `enc_bandits` | 山贼 ×2(连战两场) | deepwood 首次进入 | 不可逃;两场间不回血 |
| `enc_elite` | 寨丁头目 ×1 | gate 选 assault | 不可逃 |
| `enc_sneak` | 山贼 ×1 + 毒蛛 ×1(连战) | gate 选 sneak | 不可逃;胜后进 boss 前回满 |
| `enc_boss1` | 黑风寨主 ×1 | boss1 进入 | Boss 战,不可逃;半血进二阶段 |
## 3. 战斗状态机(完整状态转换表)
状态:`B_START → (回合循环) → VICTORY | DEFEAT | FLED`
| 状态 | 进入时副作用 | 出口转换 |
|---|---|---|
| `B_START` | 播 `btl_start_<enemy>` + 敌方登场 sfx; init 回合数=1 | 自动 → `ENEMY_TELEGRAPH`(敌方先攻的蛊师类)或 `PLAYER_SELECT`(默认玩家先攻)。第一章全部玩家先攻 |
| `PLAYER_SELECT` | 播当前指令名(`cmd_attack`),左右滑循环切换(攻击→技能→防御→道具),单击执行;上滑播战场状态;下滑请求逃跑 | 单击 → `PLAYER_EXECUTE`;下滑 → `FLEE_CHECK` |
| `PLAYER_EXECUTE` | 按指令结算:攻击=伤害公式;技能=atk×2 耗 mp3(mp 不足播 `btl_nomp` 留在本状态重选);防御=置 halfDamage 标记;道具=金疮药回 40%maxHp(无药播 `btl_noitem` 重选)。播对应 sfx + 敌方受击音 | 结算完 → `CHECK_ENEMY_DEAD` |
| `CHECK_ENEMY_DEAD` | 敌 HP≤0:播 `btl_enemy_die`;连战则拉下一个敌人回 `B_START`(不重置玩家状态) | 敌死 → `VICTORY`(无下一只);敌活 → `ENEMY_TELEGRAPH` |
| `ENEMY_TELEGRAPH` | 播敌方前摇音(`tel_<enemy>`,1.0s);启动格挡窗口 1.0s | 窗口内双击 → 格挡标记=true(`vibrate('confirm')` + `sfx/parry`),→ `ENEMY_RESOLVE`;窗口结束 → `ENEMY_RESOLVE`;窗口内其他手势 → `vibrate('error')`,留在窗口 |
| `ENEMY_RESOLVE` | 结算敌方伤害:`dmg×0.3`(格挡)/`×0.5`(防御)/全值;播受击音 + `vibrate([80])`(格挡成功不震 HIT,已震 confirm);血量档位变化时播 `btl_hp_*` | 玩家 HP≤0 → `DEFEAT`;否则回合数+1 → `PLAYER_SELECT` |
| `FLEE_CHECK` | 非 Boss 战:播 `btl_flee` 脱离;Boss/剧情战:播 `btl_noflee` 回 `PLAYER_SELECT` | → `FLED`(回场景,遭遇不消失)或 `PLAYER_SELECT` |
| `VICTORY` | 播 `btl_win` + 经验/金币获得句(整句分档,见台词表)→ 结算升级(升级播 `btl_levelup` + `vibrate('success')`)→ 写存档 | → 场景探索态 |
| `DEFEAT` | 播 `btl_lose` + 死亡归因句 → 章首(village)重生:HP/MP 回满,等级/金币/装备/flags 保留,本章非 Boss 遭遇重置 | → village 探索态 |
半血叙事钩子:敌人 HP 首次 ≤50% 时在 `CHECK_ENEMY_DEAD` 前插播 `btl_half_<enemy>`(无此语音的敌人跳过)。
## 4. 数值表
### 4.1 玩家
```
maxHp = 20 + 8*(lv-1) // lv1=20, lv3=36, lv5=52
atk = 5 + 2*(lv-1) + 武器atk
def = 护甲def
mp = 3 + lv // 破空斩耗 3
expToNext = lv * 20
dmg = max(1, round((atk攻 - def守) * (0.85~1.15)))
```
### 4.2 敌人(全游戏 8 种 + 3 Boss;第一章用前 4 种 + Boss1)
| 敌人 | 章 | HP | ATK | DEF | EXP | 金币 | 前摇音 sfx id | 前摇特征 | 半血句 |
|---|---|---|---|---|---|---|---|---|---|
| 教学野狼 | 1 | 6 | 3 | 0 | 5 | 0 | `tel_wolf` | 扑击前低吼 | 无 |
| 野狼 | 1 | 10 | 4 | 0 | 8 | 5 | `tel_wolf` | 低吼 | 无 |
| 山贼 | 1 | 16 | 6 | 1 | 12 | 12 | `tel_bandit` | 脚步+拔刀 | `btl_half_bandit` |
| 毒蛛 | 1 | 12 | 7 | 0 | 12 | 8 | `tel_spider` | 高频肢节摩擦 | 无 |
| 寨丁头目 | 1 | 24 | 8 | 2 | 20 | 25 | `tel_elite` | 重甲碰撞 | `btl_half_elite` |
| **Boss 黑风寨主** | 1 | 45 | 10 | 2 | 50 | 100 | `tel_boss1` | 双刀互击两声 | 二阶段:ATK→12,播 `boss1_phase2` |
| 沼泽鳄 | 2 | 30 | 11 | 2 | 22 | 18 | `tel_croc` | 水花+低吼 | 无 |
| 蛊师 | 2 | 22 | 12 | 1 | 26 | 30 | `tel_shaman` | 吟唱(敌方先攻) | 有 |
| 剑傀 | 3 | 38 | 14 | 3 | 40 | 45 | `tel_puppet` | 机括咔哒 | 无 |
| 影卫 | 3 | 30 | 16 | 2 | 45 | 50 | 无声(震动 DANGER 代替) | 寂静 | 有 |
| **Boss 腐沼祭主** | 2 | 70 | 14 | 3 | 90 | 200 | `tel_boss2` | 人声哼鸣 | 二阶段召唤 2 毒蛛 |
| **Boss 白无瞳** | 3 | 110 | 18 | 5 | 150 | 500 | 三阶段完全无声 | 寂静+DANGER | 三次阶段转换 |
经验校验:第一章可得 exp = 5+8+12×2+20+12+12+50 = 131+(教学狼 5 + 野狼 8 + 山贼 24 + 头目/偷袭线 20~24 + Boss 50)≈ 110-135 → 打完第一章玩家 lv3(20+40+60=120 可到 lv4 门槛前),数值节奏成立。
### 4.3 装备与道具(获取节点)
| 物品 | 效果 | 获取 |
|---|---|---|
| 铁剑 | atk+3 | village 商店 100 金(开局 50 金 + 小路调查 15 + 若干战斗;猎人支线后九折 90) |
| 皮甲 | def+2 | village 商店 80 金(九折 72) |
| 金疮药 | 回 40% maxHp | 商店 30 金;枯树洞宝箱 ×2;猎人支线 ×1;叠加上限 5 |
| 青钢剑 | atk+6 | 第二章商店 300 |
| 铁鳞甲 | def+4 | 第二章商店 250 |
| 听风剑 | atk+9,格挡窗口 1.0s→1.3s | 第三章商店 600 |
### 4.4 商店子菜单(village)
进入播 `shop_open` → 左右滑循环:铁剑/皮甲/金疮药/离开 → 单击购买(播物品名+价格档句 `shop_price_<item>`;钱不够播 `shop_poor`;已购装备播 `shop_owned`)→ 购买成功 `sfx/coin` + `vibrate([15,40,15])` → 写存档。
## 5. 探索态手势(复读总设计,施工口径)
左右滑=切选项(播选项名)/ 单击=确认 / 双击=重听场景描述+环境音 / 上滑=状态播报(`st_lv`、`st_hp_*`、`st_gold_*`、`st_equip` 链播,全整句分档)/ 下滑=菜单(继续 / 保存并回大厅 / 重听帮助)。血量档位:>70% `btl_hp_high`("你状态很好")、30-70% `btl_hp_mid`("你受了伤")、<30% `btl_hp_low`("你伤势很重")。
## 6. 存档 JSON(精确定义)
`PUT /api/progress { game: 'rpg', data: ... }` 的 `data`:
```json
{
"schema": 1,
"updatedAt": "2026-08-29T12:00:00Z",
"summary": "第一章·溪流 · Lv3 · 金币120",
"chapter": 1,
"scene": "stream",
"player": {
"lv": 3, "exp": 45,
"hp": 28, "maxHp": 36, "mp": 6,
"gold": 120,
"weapon": "iron_sword",
"armor": "leather",
"potions": 2
},
"flags": {
"tutorial_battle_done": false,
"chest_path": false,
"chest_fork": false,
"hunter_quest": false,
"shop_discount": false,
"enc_bandits_done": false,
"enc_elite_done": false,
"enc_sneak_done": false,
"boss1_done": false
},
"chapters": { "1": "open", "2": "locked", "3": "locked" },
"stats": { "kills": 0, "deaths": 0, "parries": 0, "playSec": 0 }
}
```
字段规则:
| 字段 | 默认 | 说明 |
|---|---|---|
| `schema` | 1 | 升版时 R5+ 写迁移或丢弃重来 |
| `summary` | `"新的旅程"` | 大厅卡片显示;格式 `第X章·场景名 · LvN · 金币M` |
| `chapter`/`scene` | 1 / `village` | 继续游戏落点 |
| `player.*` | lv1 exp0 hp20 maxHp20 mp4 gold50 weapon null armor null potions 1 | 开局 50 金为村长赠送剧情款 |
| `weapon`/`armor` | null | `iron_sword`/`steel_sword`/`wind_sword`;`leather`/`iron_scale` |
| `flags.*` | false | 一次性事件锁 |
| `chapters` | 见上 | `locked`/`open`/`cleared` |
| `stats.*` | 0 | 只增不减,新游戏也保留 |
- 保存时机:场景切换后、战斗结算后、商店交易后、菜单"保存并回大厅"。localStorage `soundgame.progress.rpg` 与服务器双写。
- 进游戏有存档时:播 `sys_continue_ask`("继续上次的旅程?单击继续,右滑开始新游戏。");新游戏清空 data 保留 `stats` 累计。
## 7. 资产需求清单
### 7.1 BGM(5 首,Mureka instrumental,60-90s 无缝循环,沿用归一化工艺)
| id | 用途 | Mureka prompt 草稿(英文) |
|---|---|---|
| `bgm/explore` | 第一章探索底 | "Atmospheric Chinese wuxia ambient, bamboo forest mist, sparse guzheng plucks over low drone, slow tempo 60 bpm, mysterious but calm, no vocals, seamless loop" |
| `bgm/battle` | 普通战斗 | "Tense wuxia battle music, driving taiko drums 100 bpm, sharp erhu stabs, urgent but not chaotic, no vocals, seamless loop" |
| `bgm/boss` | Boss 战 | "Epic dark wuxia boss theme, heavy taiko 120 bpm, dissonant strings, dramatic tension, no vocals, seamless loop" |
| `bgm/village` | 村庄/安全区 | "Warm peaceful Chinese village ambiance music, soft dizi flute melody, gentle plucked strings, cozy 70 bpm, no vocals, seamless loop" |
| `bgm/ending` | 章结算/剧情 | "Melancholic wuxia emotional theme, solo erhu over soft pads, bittersweet, slow, no vocals, seamless loop" |
### 7.2 SFX(35 个;SA3 = Stable Audio 3 生成,SYN = 程序合成)
| 类别 | id | 方式 | prompt 草稿 / 说明 |
|---|---|---|---|
| 敌方前摇 | `tel_wolf` | SA3 | "wolf growl then lunge, short, dry, close mic" |
| | `tel_bandit` | SA3 | "footsteps on dirt then sword unsheathing shing, 1 second" |
| | `tel_spider` | SA3 | "insect legs skittering, high frequency chitin clicks, eerie, 1 second" |
| | `tel_elite` | SA3 | "heavy armor plates clanking, menacing, 1 second" |
| | `tel_boss1` | SA3 | "two metal blades striking each other twice, dramatic ring" |
| | `tel_croc` | SA3 | "water splash with low reptile growl" |
| | `tel_shaman` | SA3 | "low guttural chant humming, ritualistic, dark" |
| | `tel_puppet` | SA3 | "wooden mechanism clicks and winding gears" |
| 战斗 | `atk_swing` | SA3 | "sword whoosh through air, fast, clean" |
| | `atk_hit` | SA3 | "sword hitting flesh, dull impact, not gory" |
| | `parry` | SA3 | "metal parry clang, bright ring, short" |
| | `skill_slash` | SA3 | "powerful sword slash with air rip, dramatic" |
| | `hurt` | SYN | 低频闷击(程序合成,避免与 atk_hit 混淆) |
| | `enemy_die` | SA3 | "body falling to ground with weapon clatter" |
| | `potion` | SA3 | "drinking liquid gulps, glass bottle" |
| | `flee` | SYN | 渐远脚步 |
| 探索/系统 | `step` | SYN | 单步脚步(复用 escape 工艺) |
| | `coin` | SYN | 硬币叮当(短合成) |
| | `chest` | SA3 | "old wooden chest creaking open" |
| | `drink_water` | SA3 | "scooping and drinking stream water" |
| | `rest` | SA3 | "settling down by campfire, fabric rustle" |
| | `levelup` | SYN | 上行钟声琶音(内容音非提示音,允许) |
| | `door_heavy` | SA3 | "heavy wooden gate slowly opening, deep creak" |
| | `ui_deny` | — | **不做**(反馈走震动 error) |
| 场景环境 | `amb_village` | SA3 | "night village ambience, campfire crackle, distant chatter, crickets, loop" |
| | `amb_path` | SA3 | "forest path ambience, wind through leaves, birds distant, loop" |
| | `amb_fork` | SA3 | "forest crossroads ambience, wind split feel, crows, loop" |
| | `amb_chest` | SA3 | "hollow tree hole ambience, drips, muffled wind, loop" |
| | `amb_stream` | SA3 | "flowing stream over rocks, gentle water, loop" |
| | `amb_hunter` | SA3 | "wood cabin ambience, firewood crackle, knife sharpening occasionally, loop" |
| | `amb_deepwood` | SA3 | "deep forest ambience, insects, distant wolf howl, ominous, loop" |
| | `amb_gate` | SA3 | "bandit camp outside gate ambience, torches burning, rowdy distant voices, loop" |
| | `amb_hall` | SA3 | "large hall ambience, fire brazier, echoing space, tense, loop" |
| 二/三章备用 | `tel_croc/tel_shaman/tel_puppet`(已列) + `amb_swamp`、`amb_peak`、`tel_boss2` | SA3 | 沼气泡/山峰风/哼鸣,R4 一起生成 |
| 格挡无声敌人 | (无 sfx,震动 DANGER) | — | 影卫/白无瞳三阶段 |
计数:前摇 8 + 战斗 9 + 探索系统 8 + 环境 9 + Boss2 前摇 1 = **35**(`ui_deny` 不做,无声敌人不占 sfx)。环境音 amb_* 走 bgm 层 loop(低音量 volume 0.5),不占 sfx 并发。
## 8. 与台词表的对应
语音 id 共 114 个(旁白双性别 ~70 + NPC 平铺单音色 ~44),见 [05-rpg-ch1-voice-ids.md](05-rpg-ch1-voice-ids.md)。场景 desc、选项名、战斗播报、商店、状态档位、教学全部覆盖;开发 agent 只许引用表内 id。