Story排版
This commit is contained in:
113
docs/story-ui-refactor-plan.md
Normal file
113
docs/story-ui-refactor-plan.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# 剧情界面与路线系统重构方案
|
||||
|
||||
> 状态:已确认,待实施
|
||||
> 更新日期:2026-07-20
|
||||
> 适用范围:`ichni Official`。本方案不涉及 `IchniCreatorStudio`。
|
||||
|
||||
## 1. 目标与原则
|
||||
|
||||
本次重构将剧情页面升级为以叙事时间推进的可拖动画面:左侧 Helper、顶部 Timeline、中心剧情树、右下章节指示器共同呈现章节进度。
|
||||
|
||||
剧情路线的排版是叙事与美术设计的一部分,因此必须由每章的 `StoryData` 静态定义;运行时仅负责生成视图、推导状态、播放动效和筛选可见信息,绝不进行自动图布局或重排。
|
||||
|
||||
## 2. 静态布局与运行时行为
|
||||
|
||||
### 2.1 StoryData 静态定义
|
||||
|
||||
每章 `StoryData` 预先保存:
|
||||
|
||||
- 全部 Block、连接关系、`gridColumn` 与 `gridRow`;
|
||||
- TextBlock 的 `Important` / `Secondary` 视觉分类;
|
||||
- Block 的解锁条件与变量驱动的互斥路线条件;
|
||||
- Timeline Marker 的锚点、文本和主线进度;
|
||||
|
||||
全局 Helper 不属于任何章节的 `StoryData`。它由独立的 `StoryHelperData` 资产保存,
|
||||
并由 `StoryManager` 统一引用;这样所有章节共享同一个 Helper 与对话池,后续只需在该资产中维护一次。
|
||||
|
||||
`gridColumn` 表示叙事时间,向右递增;`gridRow` 表示路线。主线围绕 `gridRow = 0` 排布,分支向上或向下展开。Important TextBlock 承担主线转折与章节 checkpoint,Secondary TextBlock 用于补充剧情和支线,可使用小数列位置。
|
||||
|
||||
只有叙事真正汇合时才连接到同一个后续 Block。两个结局固定在最右侧的结局区,上下分置。
|
||||
|
||||
### 2.2 运行时动态生成
|
||||
|
||||
`StoryTreeController` 根据静态蓝图动态实例化 Block、Connector 和 Timeline Marker View。路线改变时不会移动或重新排列任何节点,只更新各节点状态、连接线视觉和 Timeline 可见性。
|
||||
|
||||
## 3. Block 状态与互斥路线
|
||||
|
||||
现有状态扩展为:
|
||||
|
||||
| 状态 | 含义 |
|
||||
| --- | --- |
|
||||
| `Locked` | 当前不可用,但后续仍可能解锁。 |
|
||||
| `Current` | 当前可进入。 |
|
||||
| `Completed` | 已完成。 |
|
||||
| `Forbidden` | 已被互斥路线排除,在本章当前路线下不能再进入。 |
|
||||
|
||||
每个 Block 同时拥有 `unlockCondition` 与 `forbiddenCondition`,二者均使用通用的 `StoryCondition` 条件树。`unlockCondition` 留空表示可解锁;`forbiddenCondition` 留空表示不会被条件禁用。运行时若 `forbiddenCondition` 先满足,则 Block 进入 `Forbidden`,优先于 Completed / Current / Locked。
|
||||
|
||||
路线使用普通剧情变量配置:例如 `chapter0_route_main = 1` 表示上方路线、`= 2` 表示下方路线。上方 Block 可将 `unlockCondition` 设为 `chapter0_route_main == 1`,并在 `forbiddenCondition` 中设为 `chapter0_route_main == 2`;下方 Block 使用相反配置。这样路线选择、教程、Yarn 条件与其它剧情判断完全共用同一种条件语法。
|
||||
|
||||
Forbidden Block 保留在剧情树中、不响应点击,并通过预留的视觉函数显示专用图片或文本。关联 Connector 可同步使用低透明度或失效视觉。Timeline 不显示 Forbidden 路线的 Marker。
|
||||
|
||||
## 4. Timeline
|
||||
|
||||
Timeline 表达章节内的叙事时间,而非章节列表。
|
||||
|
||||
每个 Marker 单独配置:
|
||||
|
||||
- `markerId`;
|
||||
- `anchorBlockId`:唯一的位置来源;
|
||||
- 本地化时间文本或特殊自定义文本;
|
||||
- `progressValue`:0 至 1 的章节主线进度;
|
||||
- 可选路线条件。
|
||||
|
||||
运行时直接读取目标 Block 的 `gridColumn` 计算 Marker 横坐标。Timeline 固定在屏幕顶部,并随剧情树横向拖动同步移动;纵向拖动不影响 Timeline。
|
||||
|
||||
Marker 锚定的 TextBlock 为 `Current` 或 `Completed` 时显示;处于 `Locked` 或 `Forbidden` 时隐藏。章节进度只取所有已完成、有效 Marker 中最大的 `progressValue`;两条不同结局都设置为 `1.0`,支线不参与主线百分比计算。
|
||||
|
||||
## 5. Helper
|
||||
|
||||
Helper 使用独立的场景内 `HelperTalk` 面板,不使用模态 `MessageUIPage`。
|
||||
|
||||
`StoryHelperData` 是独立的全局 ScriptableObject。每条候选对话可包含本地化文本、剧情/路线条件和权重。当前版本从所有条件满足的候选中随机抽取,并在候选数量大于一时避免连续重复;无可用候选时使用默认兜底对话。
|
||||
|
||||
未来可在不改变 UI 架构的前提下,按剧情变量、时间阶段、路线、角色状态等扩展筛选规则。
|
||||
|
||||
## 6. SongBlock
|
||||
|
||||
- 点击 SongBlock 后进入选曲页面,并优先选中其配置的目标歌曲;
|
||||
- 仅进入选曲页面或直接返回,不完成 SongBlock;
|
||||
- 玩家确认进入目标歌曲时,立刻完成该 SongBlock;之后中途退出游戏不回滚;
|
||||
- 改选其他歌曲进入游戏,不完成原 SongBlock;
|
||||
- 返回选曲或剧情时保留来源上下文,回到剧情页面后恢复章节、焦点 Block 与剧情树视口位置。
|
||||
|
||||
## 7. Important TextBlock 与章节 checkpoint
|
||||
|
||||
每个 Important TextBlock 都可作为本章重开点。系统为其保存“进入该 Block 之前”的章节快照:
|
||||
|
||||
- `checkpointBlockId`;
|
||||
- 已完成 Block 集合;
|
||||
- 本章剧情变量;
|
||||
- 本章选项与路线变量。
|
||||
|
||||
点击已完成的 Important TextBlock 时,提供“回顾剧情 / 从此处重新开始 / 取消”。选择重开会用 checkpoint 覆盖当前章节的剧情状态、将该 Block 恢复为 `Current`、重建剧情树并从该 Yarn Node 开始。
|
||||
|
||||
重开只改变本章的剧情相关数据;不会回滚歌曲成绩、设置、永久内容解锁 Key 或其他章节的进度。
|
||||
|
||||
## 8. 章节独立性
|
||||
|
||||
剧情变量、选项、路线和 checkpoint 都必须按章节保存与读取。Chapter 0 的剧情选择或重开不会影响 Chapter 1。
|
||||
|
||||
歌曲成绩、Settings 和永久内容解锁属于全局系统,不纳入章节 checkpoint 的回滚范围。
|
||||
|
||||
## 9. 实施顺序
|
||||
|
||||
1. 重构 StoryData 与章节级剧情存档的数据契约。
|
||||
2. 增加 `Forbidden` 状态、通用 `StoryCondition` 与 Block 视觉接口。
|
||||
3. 移除 Block 基类的固定尺寸覆盖,改由 Prefab/Visual Preset 决定尺寸。
|
||||
4. 实现 Timeline Marker、横向同步和主线进度计算。
|
||||
5. 实现 SongBlock 到选曲、GameScene、剧情页面的完整返回上下文。
|
||||
6. 实现 Helper 对话池。
|
||||
7. 实现 Important TextBlock checkpoint 与章节重开流程。
|
||||
8. 配置 Chapter 0 的真实布局、时间点和两条结局。
|
||||
9. 完成 PC、Android、iOS 的路线、重开、拖动、Safe Area 和存档回归测试。
|
||||
@@ -7,7 +7,7 @@ TutorialBlock 点击后通过通用 `SelectionBox` 动态生成“游玩教程 /
|
||||
1. 将 TutorialBlock 的 `tutorialProgressVariable` 写为 `true`。
|
||||
2. 保存全局剧情变量。
|
||||
3. 将该 TutorialBlock 标记为 Completed,用于故事树的节点外观;Completed 状态仍允许玩家再次点击回顾教程。
|
||||
4. 重新计算所有 StoryBlock 的 `UnlockCondition`。
|
||||
4. 重新计算所有 StoryBlock 的条件状态(`unlockCondition` 与 `forbiddenCondition`)。
|
||||
|
||||
后续 Block 必须通过 `VariableCondition` 读取教程变量解锁,不要依赖 TutorialBlock 的完成记录。选择“游玩教程”后会进入 GameScene;选择“跳过教程”则留在故事树。教程游玩中退出、失败或关闭游戏不会回退已经确认的解锁状态。教程节点完成后仍可再次点击;重复游玩只会重写相同的已处理状态,不会影响已解锁的后续剧情。
|
||||
|
||||
@@ -62,7 +62,7 @@ TutorialBlock 点击后通过通用 `SelectionBox` 动态生成“游玩教程 /
|
||||
| `nextBlockIds` | 第一个后续剧情节点,例如 `A-0` |
|
||||
| `unlockCondition` | 留空,使教程节点在章节开始时可点击 |
|
||||
|
||||
3. 为原本的第一个剧情节点 `A-0` 设置 `UnlockCondition`:选择 `VariableCondition`,并填写:
|
||||
3. 为原本的第一个剧情节点 `A-0` 设置 `unlockCondition`:选择 `VariableCondition`,并填写:
|
||||
|
||||
| 字段 | 值 |
|
||||
|---|---|
|
||||
|
||||
Reference in New Issue
Block a user