Story排版

This commit is contained in:
SoulliesOfficial
2026-07-20 16:56:04 -04:00
parent 04ec368a59
commit c30bb258b1
107 changed files with 7794 additions and 969 deletions

View 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 承担主线转折与章节 checkpointSecondary 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 和存档回归测试。

View File

@@ -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`,并填写:
| 字段 | 值 |
|---|---|