From c75db2886f9487f65f1853f4a800deaf9046eb71 Mon Sep 17 00:00:00 2001 From: cocos02 Date: Sun, 14 Jun 2026 16:42:16 +0800 Subject: [PATCH] docs: add battle system, conditional routing, key moments, and creators guide docs --- docs/guide/BATTLE_SYSTEM.md | 112 ++++++++++++++++++++++++++++++ docs/guide/CONDITIONAL_ROUTING.md | 36 ++++++++++ docs/guide/CREATORS_GUIDE.md | 15 ++++ docs/guide/KEY_MOMENTS.md | 31 +++++++++ docs/guide/SCENE_JSON_SPEC.md | 65 +++++++++++++++-- 5 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 docs/guide/BATTLE_SYSTEM.md create mode 100644 docs/guide/CONDITIONAL_ROUTING.md create mode 100644 docs/guide/CREATORS_GUIDE.md create mode 100644 docs/guide/KEY_MOMENTS.md diff --git a/docs/guide/BATTLE_SYSTEM.md b/docs/guide/BATTLE_SYSTEM.md new file mode 100644 index 0000000..a1cbe71 --- /dev/null +++ b/docs/guide/BATTLE_SYSTEM.md @@ -0,0 +1,112 @@ +# 战斗系统 + +## 概述 + +P31 新增。分为两个独立功能:**战斗 HUD**(战斗中显示)和**战斗结算**(胜利后弹出)。 + +--- + +## BattleHUD — 战斗中显示的角色属性 + +配置在 `SceneNode.battleHUD`。 + +```json +{ + "battleHUD": [ + { + "label": "主角", + "labelKey": "battle.hud.player", + "portrait": "images/player.jpg", + "stats": [ + { "variable": "player_hp", "label": "HP", "labelKey": "stat.hp", "max": 100 }, + { "variable": "player_mp", "label": "MP", "labelKey": "stat.mp", "max": 50 }, + { "variable": "score", "label": "连击", "labelKey": "stat.combo" } + ] + } + ] +} +``` + +| stat 字段 | 说明 | +|-----------|------| +| `variable` | 变量名,值随 effect 实时变化 | +| `label` | 显示标签(回退值) | +| `labelKey` | i18n key | +| `max` | 最大值,有则为进度条,无则为纯数字 | +| `style` | 强制 `"bar"` 或 `"number"`。没配时根据有无 `max` 自动 | + +进度条颜色根据百分比自动变化:100-50% 绿色 / 50-25% 橙色 / 25-0% 红色。 + +--- + +## BattleResult — 胜利结算面板 + +配置在 `SceneNode.battleResult`。视频播放完后自动弹出。 + +```json +{ + "battleResult": { + "title": "击退成功!", + "titleKey": "battle.result.victory", + "stats": [ + { "label": "勇气", "labelKey": "stat.courage", "variable": "courage", "max": 100 }, + { "label": "QTE 成功", "labelKey": "stat.qte_succeeded", "variable": "qte_succeeded" } + ] + } +} +``` + +| 字段 | 说明 | +|------|------| +| `title` | 结算标题(回退值) | +| `titleKey` | 标题 i18n key | +| `stats` | 统计项数组。`variable` / `label` / `labelKey` / `max` | + +### 关键规则 + +- 战败场景**不配** `battleResult`——战败直接走视频叙事 +- 结算面板关闭后自动跳转到 `nextScene` 或第一项 `choice` 目标 +- stats 数量随意增减,面板自动适配 + +--- + +## 完整模板 + +```json +{ + "id": "combat", + "videoUrl": "combat/video.mp4", + "battleHUD": [ ... ], + "qte": { + "successScene": "combat_router", + "failScene": "defeat", + "effects": { + "success": [{ "type": "add", "target": "enemy_hp", "value": -25 }], + "fail": [{ "type": "add", "target": "player_hp", "value": -20 }] + } + }, + "nextScene": "combat_router" +}, +{ + "id": "combat_router", + "keyMoment": false, + "nextScene": [ + { "conditions": [{ "variable": "enemy_hp", "op": "<=", "value": 0 }], "targetScene": "victory" }, + { "conditions": [{ "variable": "player_hp", "op": "<=", "value": 0 }], "targetScene": "defeat" }, + { "targetScene": "combat" } + ] +}, +{ + "id": "victory", + "videoUrl": "victory/video.mp4", + "battleResult": { "title": "胜利!", "stats": [ ... ] }, + "nextScene": "next_chapter" +}, +{ + "id": "defeat", + "videoUrl": "defeat/video.mp4", + "keyMoment": true, + "onEnter": [{ "type": "set", "target": "player_dead", "value": 1 }], + "nextScene": "game_over" +} +``` diff --git a/docs/guide/CONDITIONAL_ROUTING.md b/docs/guide/CONDITIONAL_ROUTING.md new file mode 100644 index 0000000..5c5b50d --- /dev/null +++ b/docs/guide/CONDITIONAL_ROUTING.md @@ -0,0 +1,36 @@ +# 条件路由 + +## 概述 + +P25 新增。`nextScene` 从单一场景 ID 扩展为**条件路由数组**。 +第一个满足 `conditions` 的场景自动跳转,末尾无条件项作为默认兜底。 + +## 基本用法 + +```json +{ + "id": "combat_router", + "keyMoment": false, + "nextScene": [ + { "conditions": [{ "variable": "enemy_hp", "op": "<=", "value": 0 }], "targetScene": "victory" }, + { "conditions": [{ "variable": "player_hp", "op": "<=", "value": 0 }], "targetScene": "defeat" }, + { "targetScene": "combat" } + ] +} +``` + +**解读:** 敌人 HP ≤ 0 → 胜利 / 自己 HP ≤ 0 → 战败 / 否则 → 回到战斗场景循环。 + +## 配合 QTE 使用 + +``` +QTE 成功 → effects: enemy_hp -= 25 + → successScene = "combat_router" + ├── enemy_hp <= 0 → victory 场景 + ├── player_hp <= 0 → defeat 场景 + └── 否则 → 回到 QTE 场景(循环) +``` + +## 向后兼容 + +旧的 `"nextScene": "alone_ending"` 写法**完全不受影响**。引擎自动区分字符串和数组。 diff --git a/docs/guide/CREATORS_GUIDE.md b/docs/guide/CREATORS_GUIDE.md new file mode 100644 index 0000000..9de844f --- /dev/null +++ b/docs/guide/CREATORS_GUIDE.md @@ -0,0 +1,15 @@ +# 创作者指南 + +本文档集涵盖所有剧作和功能配置的教程。 + +| 文档 | 说明 | +|------|------| +| [QUICK_START.md](QUICK_START.md) | 快速上手——5 分钟跑通第一个场景 | +| [SCENE_JSON_SPEC.md](SCENE_JSON_SPEC.md) | 所有字段的完整参考手册 | +| [BRANCHING.md](BRANCHING.md) | 基本分支、条件分支、隐藏选项 | +| [CONDITIONAL_ROUTING.md](CONDITIONAL_ROUTING.md) | `nextScene` 数组——条件路由(P25) | +| [KEY_MOMENTS.md](KEY_MOMENTS.md) | StoryGallery 关键节点过滤(P26) | +| [BATTLE_SYSTEM.md](BATTLE_SYSTEM.md) | 战斗 HUD + 战斗结算面板(P31) | +| [INTERACTIONS.md](INTERACTIONS.md) | QTE、热点、循环等待 | +| [I18N.md](I18N.md) | 多语言字幕和 UI 国际化 | +| [PUBLISHING.md](PUBLISHING.md) | 打包发布——Web zip / macOS / Windows | diff --git a/docs/guide/KEY_MOMENTS.md b/docs/guide/KEY_MOMENTS.md new file mode 100644 index 0000000..a1789f5 --- /dev/null +++ b/docs/guide/KEY_MOMENTS.md @@ -0,0 +1,31 @@ +# 关键节点过滤 + +## 概述 + +P26 新增。StoryGallery 的章节回顾默认只展示**剧情关键节点**,过滤掉过渡/路由/中间场景。 + +## 自动判断规则 + +| 场景类型 | 是否展示 | +|----------|:--:| +| 章节起始场景(`chapters[].startScene`) | ✅ | +| 有 `choices` 的分支点 | ✅ | +| 结局场景(`endings[].sceneId`) | ✅ | +| QTE 场景 | ❌ | +| 路由/过渡场景 | ❌ | + +## 手动覆盖:`keyMoment` 字段 + +```json +{ + "id": "combat_router", + "keyMoment": false, + "nextScene": [...] +} +``` + +| 值 | 行为 | +|:--:|------| +| `true` | 强制展示 | +| `false` | 强制隐藏 | +| 未设置 | 自动判断 | diff --git a/docs/guide/SCENE_JSON_SPEC.md b/docs/guide/SCENE_JSON_SPEC.md index 31f7ba7..259b67a 100644 --- a/docs/guide/SCENE_JSON_SPEC.md +++ b/docs/guide/SCENE_JSON_SPEC.md @@ -48,7 +48,7 @@ interface SceneNode { choices?: Choice[] hotspots?: Hotspot[] qte?: QTEDefinition - nextScene?: string + nextScene?: string | Choice[] onEnter?: Effect[] loopStart?: number loopEnd?: number @@ -59,6 +59,9 @@ interface SceneNode { bgmDuckFade?: number videoMuted?: boolean skippable?: boolean + keyMoment?: boolean + battleHUD?: BattleHUDEntry[] + battleResult?: BattleResultDef } ``` @@ -76,7 +79,7 @@ interface SceneNode { | `choices` | Choice[] | 选项列表 | | `hotspots` | Hotspot[] | 可点击热点区域 | | `qte` | QTEDefinition | QTE 定义 | -| `nextScene` | string | 无选项时的默认跳转场景 | +| `nextScene` | string \| Choice[] | 无选项时的默认跳转。字符串为单一场景 ID;数组为条件路由,遍历第一个满足 conditions 的跳转。末尾无条件项作为默认目标 | | `onEnter` | Effect[] | 进入场景时触发的效果 | | `loopStart` | number | 循环起始时间(秒) | | `loopEnd` | number | 循环结束时间(秒)。视频播放到 loopEnd 时跳回 loopStart | @@ -87,6 +90,9 @@ interface SceneNode { | `bgmDuckFade` | number | BGM Duck 过渡时长(秒),默认 0.5 | | `videoMuted` | boolean | 视频静音(配合独立 BGM 使用) | | `skippable` | boolean | `false` = 禁止跳过(用于 QTE 等关键场景) | +| `keyMoment` | boolean | StoryGallery 中是否展示为关键节点。`true`=强制展示,`false`=强制隐藏,未设置时自动判断(章节起始/有 choice/是结局) | +| `battleHUD` | BattleHUDEntry[] | 战斗场景中显示的角色属性 HUD。每个 entry 为一个角色(头像 + stats 列表) | +| `battleResult` | BattleResultDef | 胜利结算面板。视频结束后弹出,展示战斗统计数据。战败场景不配置此字段 | --- @@ -111,7 +117,6 @@ interface Choice { | `textKey` | i18n key,优先于 `text`。如 `"intro.choice.left_door"` | | `prompt` | 选择后浮现的提示文字(回退值) | | `promptKey` | prompt 的 i18n key。如 `"left_door.prompt.handshake"`。优先于 `prompt` | -| `promptKey` | prompt 的 i18n key。如 `"left_door.prompt.handshake"` | | `targetScene` | 目标场景 ID | | `conditions` | 显示条件,不满足的选项隐藏 | | `effects` | 选择后触发的效果 | @@ -178,7 +183,6 @@ interface QTEDefinition { | `triggerTime` | 触发时间(秒),视频播放到此时间弹出 QTE | | `prompt` | 提示文字(回退值) | | `promptKey` | i18n key。如 `"right_door.qte.dodge"`。优先于 `prompt` | -| `promptKey` | i18n key。如 `"right_door.qte.dodge"` | | `keys` | 有效按键列表,如 `["ArrowLeft", "ArrowRight", "a", "d"]` | | `timeLimit` | 限时秒数 | | `successScene` | 成功跳转场景 | @@ -295,3 +299,56 @@ interface LocalesConfig { |------|------| | `path` | 语言文件目录(相对于 `assetBase`),如 `"locales/"` | | `languages` | 支持的语言列表,如 `["zh", "en", "ja"]` | + +### BattleHUDEntry / BattleHUDStat + +战斗场景中显示的角色属性 HUD。配置在 `SceneNode.battleHUD`。 + +```typescript +interface BattleHUDEntry { + label: string + labelKey?: string + portrait?: string + stats: BattleHUDStat[] +} + +interface BattleHUDStat { + variable: string + label: string + labelKey?: string + max?: number + style?: 'bar' | 'number' +} +``` + +| 字段 | 说明 | +|------|------| +| `label` | 角色名称(回退值) | +| `labelKey` | 角色名称 i18n key | +| `portrait` | 角色头像路径 | +| `stats` | 属性数组。`variable`/`label`/`labelKey`/`max`/`style`。`style` 缺省时根据有无 `max` 自动判断(有则为 bar,无则为 number) | + +### BattleResultDef / BattleResultStat + +战斗胜利结算面板。配置在 `SceneNode.battleResult`。 + +```typescript +interface BattleResultDef { + title: string + titleKey?: string + stats: BattleResultStat[] +} + +interface BattleResultStat { + label: string + labelKey?: string + variable: string + max?: number +} +``` + +| 字段 | 说明 | +|------|------| +| `title` | 结算标题(回退值) | +| `titleKey` | 标题 i18n key | +| `stats` | 统计项数组。`variable`/`label`/`labelKey`/`max` |