存档重构,游戏内容解锁机制;教程完善(未完成)

This commit is contained in:
SoulliesOfficial
2026-07-18 16:51:18 -04:00
parent d48ef1e65e
commit dda354ebb9
123 changed files with 4032 additions and 558 deletions

View File

@@ -0,0 +1,323 @@
# ChatGPT / Codex 辅助 UI 与美术资产工作流
> 文档状态Active
> 首次建立2026-07-18
> Scope 更新2026-07-18 — Chapter 0 首发Windows、Android、iOS`en`、`zh-CN`、`ja`、`ko`、`vi-VN`
> 适用项目:`ichni Official`
> 关联路线图:`docs/release-readiness-roadmap.md` 的 `UI-001``UI-007`
## 1. 结论
**目前可以使用 ChatGPT/Codex 辅助 ichni 的 UI 优化和美术资产重制,并且不需要先雇佣其他人。** 当前工具可以根据文字或参考图生成、编辑 Raster Image适合制作
- 对话界面背景、章节背景、装饰性插画和氛围图。
- UI Panel、Frame、Divider、Button Skin、Badge 和装饰层的视觉方案。
- Icon 方向探索、Loading Illustration、Placeholder、Sprite Sheet 初稿。
- 根据现有 Mockup 做局部替换、去除元素、改色、扩图、重新构图。
- 从一个成熟页面提炼同系列视觉变体,建立统一风格。
它不能独立保证以下生产要求:
- 自动交付结构准确、命名规范且完全可编辑的 PSD/Figma Layer。
- 像素级一致的多状态组件、精确 9-slice 边界、可靠 Vector/SVG。
- 直接在图片中生成大量正确的中英日韩越正式文本。
- 自动完成 Alpha Edge、Texture Compression、Sprite Slice、Prefab State 和多分辨率验证。
- 自动判断每一项训练/参考/第三方素材的商业许可。
因此推荐“**AI 生成/定向编辑 + 免费图形工具清理 + Codex 自动化检查 + Unity 真机验证**”的混合流程。
本轮只服务 Chapter 0 首发。Chapter 1 的 UI/背景只能在不影响 Chapter 0 的设计、实现、LQA 和三平台性能验证时制作;`IchniCreatorStudio` 不在此工作流范围内。
OpenAI 当前官方说明支持在 Codex 中使用 `$imagegen`,也可以用 Image Generation API 做批量生产;官方建议使用少量参考图、短而具体的 Prompt、一次只做一个定向修改并把复杂文字排版留到设计工具中完成
- [OpenAI Image Generation in Codex](https://learn.chatgpt.com/docs/image-generation)
- [OpenAI Image Generation API Guide](https://developers.openai.com/api/docs/guides/image-generation)
## 2. ichni 当前视觉基线
### 已有优势
- 已形成深蓝、青色高光、轨道/圆环/细线装饰、低饱和背景的可识别风格。
- Start、Chapter Selection、Song Selection、Settings、Dialogue、Summary 都已有整屏视觉参考。
- 多数页面已有拆分 Sprite 和 Prefab 基础,不需要从空白重新设计整个产品。
- 视觉语言与音游、轨道、星空/轨道站意象相符,适合建立 Original Style Guide 后继续扩展。
### 当前风险
- 背景纹理和装饰层偏密集,小字号与低对比标签容易被吞没。
- 多处 Icon-only Control缺少 Hover/Focus/Disabled 和可访问性定义。
- Scene 中混用 `1920×1080``2560×1440` Reference Resolution移动端 Safe Area 尚未建立。
- Runtime `Assets` 中同时存在大体积 PSD、整屏 Mockup 和拆分图,源文件与运行时导出没有清晰边界。
- Scene 仍有硬编码/测试文本;如果文字继续烘焙进图片,会扩大本地化和返工成本。
- 许多 UI Texture 的实际用途、状态和引用尚无 Manifest批量重制容易产生孤儿资产或破坏 Prefab 引用。
## 3. 先建立的三条原则
1. **文字不进入背景图。** 所有会本地化、变化或显示数据的文字都使用 TMP/Localization图片只包含不可读的抽象纹理和装饰。
2. **先拆 UI 责任,再生成图片。** AI 不负责决定 Screen Flow、信息层级和 Interaction State先完成 UI Inventory 和 Design Tokens。
3. **每次只验证一个小批次。** 先做 Dialogue Pilot进入 Unity 验证后,再扩到其他 Screen避免批量生成一套无法切片或不可读的资产。
## 4. 免费工具组合
| 任务 | 推荐工具 | 用途 |
|---|---|---|
| 生成与定向修改 | ChatGPT/Codex `$imagegen` | Background、Illustration、Panel/Frame 方案、局部编辑 |
| 批量生成 | OpenAI Image Generation API | 经 Pilot 批准后的受控批次与变体 |
| Raster 清理 | Krita / GIMP / Photopea | Mask、Alpha、Layer、Color、Edge Cleanup、PSD 导出 |
| Vector/Icon | Inkscape | 几何 Icon、SVG、可缩放线条和 Logo 形状 |
| Unity 集成 | Unity Sprite Editor / SpriteAtlas | Slice、Border、Packing、Compression、Prefab State |
| 自动验证 | Codex 编写 Editor Tool / CI Validator | Naming、Dimensions、Import Settings、Missing Reference、Build Size |
不雇佣其他人的可行性取决于 Scope背景、Panel、装饰和有限 Icon 可以由现有团队完成如果要求大量高精度角色立绘、复杂动画、Logo 品牌系统或多章节插画,仍应先缩小首发资产数量,而不是让 AI 无限制扩张内容。
## 5. 资产生产管线
### Stage A — UI Inventory
在生成任何新资产前,为每个 Screen 建立清单:
| Field | 示例 |
|---|---|
| Asset ID | `UI-DIALOG-BG-001` |
| Screen | Dialogue |
| Role | Background / Frame / Panel / Button / Icon / Decoration |
| Current Path | `Assets/Sprites/UITextures/...` |
| Prefab/Scene References | Dialogue Prefab、`MenuScene` |
| State | Normal / Hover / Pressed / Selected / Disabled / Focused |
| Size / Aspect | 2560×1440、9-slice、64×64 等 |
| Locale Text | 必须为 `None`,文字由 TMP 承担 |
| Replace / Keep | 要替换的层与必须保留的层 |
| Owner / Status | TODO / REVIEW / APPROVED / IN UNITY / DONE |
Inventory 完成后,才能判断哪些整屏图片只是 Reference哪些 Sprite 被 Runtime 真正引用。
### Stage B — Lightweight Art Bible
至少定义:
- Color TokensBackground、Surface、Primary Cyan、Secondary Blue、Warning、Error、Disabled、Text Levels。
- TypographyTMP Font、Size Scale、Line Height、CJK/Latin Fallback、数字样式。
- ShapeCorner Radius、Line Width、Panel Border、Cut Corner、Orbit Motif 使用密度。
- Spacing4/8 px Grid 或项目选择的统一 Grid。
- Lighting高光方向、Glow 强度、是否允许 Bloom-like Edge。
- TextureNoise 粒度、背景对比、装饰透明度上限。
- Motion出现/消失时长、Easing、Focus/Selected 反馈。
- Accessibility最小文字尺寸、最低对比、状态不能只依赖颜色。
描述风格时使用原创特征,例如:
> Original dark navy and cyan sci-fi rhythm-game interface, restrained orbital-line motifs, layered translucent panels, precise geometric framing, quiet star-field ambience, high readability, no text, no logo, no imitation of any named artist or franchise.
不要要求模仿具体在世艺术家、品牌或游戏的独特风格。
### Stage C — Decompose Full-screen Mockup
整屏 UI 应拆成以下层:
1. `Background`:全屏、无文字、低信息密度,可按 Aspect Crop/Extend。
2. `Atmosphere`Glow、Dust、Stars、Fog必要时独立以控制透明 Overdraw。
3. `Structural Frame`:顶栏、底栏、边框、轨道线;优先 Vector 或 9-slice。
4. `Panel Skin`:可重复使用的 9-slice Surface不给每个 Screen 单独生成一张。
5. `Decorative Overlay`:非交互性的角花、圆环、扫描线;数量要受性能预算约束。
6. `Interactive Components`Button、Tab、Slider、Toggle、Dropdown每个状态明确。
7. `Icons`:统一 Grid、Stroke、Padding、Optical Weight。
8. `Text/Data`:全部由 TMP、Localization 和 Runtime Data 渲染。
AI 最适合负责 1、2、5 和部分 3/4 的视觉素材6、7 最终应由规则化组件和 Vector/手工清理保证一致性。
### Stage D — Generate / Edit
每次请求必须包含四部分:
1. **Context**:它属于哪个 Screen、玩家在做什么。
2. **Keep**:现有参考图中必须保留的构图、色彩或留白区域。
3. **Change**:本轮只改变什么。
4. **Output Contract**尺寸、Aspect、Alpha、是否 Tileable、是否无文字、留白和导出用途。
示例:
```text
Using the attached ichni dialogue mockup as a visual reference, create an original
2560x1440 dialogue background layer only. Keep the dark navy/cyan palette, orbital
line motifs, and the quiet sci-fi station atmosphere. Remove every panel, portrait,
button, icon, logo, and all readable text. Reserve calm low-detail negative space in
the lower 38% for the dialogue panel and on the left 28% for a character portrait.
Avoid bright focal points behind future text. Full-bleed raster background, no frame,
no watermark, no embedded typography.
```
Panel Skin 示例:
```text
Create one original transparent PNG UI panel skin for ichni: a dark navy translucent
surface with a restrained cyan 2 px geometric border and subtle cut corners. Front
view, perfectly rectangular, symmetrical, no perspective, no glow outside the canvas,
no text, no icon, no logo, large clean center, designed for 9-slice use. Provide one
normal-state asset; do not create a screen mockup.
```
局部编辑示例:
```text
Edit only the highlighted upper-right decoration. Reduce its brightness and visual
density by about one third so it no longer competes with the title. Keep all other
pixels, dimensions, palette, composition, and transparency unchanged.
```
如果结果不理想,下一轮只提出一个具体修改,例如“扩大底部留白”“降低背景亮点”“保持边框不动,仅移除文字”,不要同时重新设计所有层。
### Stage E — Cleanup and Export
AI Output 进入 Unity 前必须经过:
- 删除假文字、Watermark-like Shape、脏边和随机不可解释细节。
- 检查 Alpha Premultiplication、半透明边缘和深色背景 Halo。
- 几何边框重新拉直;需要精确重复的形状用 Inkscape/Krita 重建。
- 对 9-slice 资产保证四角固定、边缘可拉伸、中心无不可拉伸纹理。
- 保留 Working SourceKrita/PSD/SVG与最终 PNG不要只保存聊天输出。
- 生成时的 Prompt、Reference、Model/Date 和人工修改说明进入 Manifest。
推荐未来目录:
```text
ArtSource/
UI/
Dialogue/
Working/
References/
Prompts/
Assets/
Sprites/
UITextures/
Dialogue/
Backgrounds/
Panels/
Icons/
```
`ArtSource` 是否放在主 Git、Git LFS 或独立美术仓库应另行决定。在完成引用审计之前,不要直接移动当前 PSD/PNG先复制、重新导出、替换引用再删除旧资产。
### Stage F — Unity Import
推荐默认值需按目标平台复核:
| 类型 | Texture Type | Mip Maps | Alpha | Compression | 备注 |
|---|---|---|---|---|---|
| UI Background | Sprite (2D and UI) | Off | 按需 | 平台压缩 | 控制 Max Size避免不必要的 Alpha |
| Panel / Button | Sprite (2D and UI) | Off | On | 高质量/平台适配 | 配置 Border验证 Pixel Edge |
| Icon | Sprite (2D and UI) | Off | On | 高质量 | 统一 PPU、Padding、尺寸 |
| Repeatable Pattern | Sprite / Default | 视 Shader | 按需 | 平台适配 | 验证 Wrap Mode 与 Seams |
集成检查:
- Sprite 引用落在 Prefab而不是只在 Scene 内临时替换。
- Button 的 Normal/Highlighted/Pressed/Selected/Disabled/Focused 状态齐全。
- Dynamic Batching 不是透明 UI 性能解决方案;用 Canvas 分组、Atlas、覆盖面积和 Overdraw 实测。
- 进入 SpriteAtlas 后检查 Padding、Alpha Bleed、Build Size 和首屏加载。
- 目标 Locale 文本使用 TMP Overlay 验证,不得回到烘焙文字。
### Stage G — Review and Approve
只有同时通过四个 Gate 才能标记 `APPROVED`
1. **Visual Gate**:符合 Art Bible、层级清楚、不抢文字、同系列一致。
2. **UX Gate**信息与交互优先级正确所有状态可识别Keyboard/Controller/Touch 可用。
3. **Technical Gate**尺寸、Alpha、9-slice、Import、Atlas、Memory、Overdraw、Safe Area 合格。
4. **Rights Gate**来源、Prompt、Reference 权限和人工修改有记录,没有未经授权的 Logo/角色/商标。
## 6. 推荐的 Dialogue Pilot
第一轮只制作以下资产:
- `UI-DIALOG-BG-001`:无文字 Dialogue Background。
- `UI-PANEL-BASE-001`:通用 9-slice Panel Skin。
- `UI-BUTTON-PRIMARY-001`Normal、Highlighted/Focused、Pressed、Disabled 四个 State。
- `UI-DIALOG-DECOR-001`:一组低密度装饰 Overlay。
Pilot 步骤:
1. 从现有 Dialogue Mockup 导出一张 Reference并标记必须保留/删除区域。
2. 为四个资产分别写 Asset Contract不要求一次生成整屏成品。
3.`$imagegen` 生成 24 个方向,只选择一个继续。
4. 在 Krita/GIMP/Inkscape 完成精确 Layer、Alpha、Border 和状态变体。
5. 在一个复制的 Dialogue Prefab/测试 Scene 中集成,避免直接覆盖生产 Prefab。
6.`1920×1080``2560×1440`、16:10、Android 刘海/挖孔设备与 iOS Safe Area 截图对比;首发固定横屏。
7. 对比旧版/新版的文字对比度、Draw Calls、Texture Memory、Overdraw 和加载时间。
8. 只有通过 Review Gate 后,才扩展到 Start、Chapter、Song Selection、Settings、Summary。
## 7. Codex 可以进一步自动化的工作
在 Pilot 规格稳定后,可以让 Codex 实现以下 Unity Editor 工具:
- 扫描 UI Texture 的 Naming、尺寸、Texture Type、Mip Maps、Alpha、Compression、Max Size。
- 输出“Sprite → Prefab/Scene”引用报告辅助安全清理旧 PSD/PNG。
- 读取 Asset Manifest检查缺失 State、Locale Text 烘焙风险和未批准资产。
- 批量创建/更新 SpriteAtlas 和平台 Override但必须先由项目确认规范。
- 生成多分辨率 Screenshot Matrix辅助人工视觉回归。
- 扫描 Scene/Prefab 中硬编码 TMP 文本和缺失 Localization Key。
- 统计 Texture Memory、StreamingAssets 平台冗余与 Build Size 变化。
这些自动化应在 Pilot 确认后编写,否则工具会把尚未决定的美术规范固化到工程里。
## 8. AI Asset Manifest 模板
建议保存为 CSV/JSON至少包含
```text
asset_id
screen
role
source_path
runtime_path
dimensions
alpha_required
slice_border
states
prompt_version
reference_ids
reference_rights
generation_date
manual_edits
unity_import_profile
prefab_references
review_status
reviewer
notes
```
命名示例:
```text
ui_dialog_bg_ch00_v001.png
ui_panel_base_9s_v003.png
ui_button_primary_normal_v002.png
ui_button_primary_focused_v002.png
ui_icon_settings_gear_v001.png
```
不要把“final”写进文件名版本和 Approval 状态由 Manifest 管理。
## 9. 质量与安全红线
- 不生成或保留可识别的第三方 Logo、角色、UI Trade Dress 或受保护品牌元素。
- 不用具体艺术家/游戏名要求模仿;用颜色、构图、材质、密度、光线、形状等可验证特征描述。
- 不让 AI 在资产里生成玩家会阅读的正式文本。
- 不直接覆盖现有生产资产先做新文件、替换引用、A/B 验证,再清理旧资源。
- 不因为“看起来更精细”就接受更高的 Texture Memory、透明覆盖和 Loading 成本。
- 不批量生成大量近似资产;优先复用 Panel、Icon Grid、Token 和 Shader。
- 不把聊天记录当作唯一 Source保存 Prompt、Reference、Working File 和 Export。
## 10. 何时可以开始
满足以下条件即可开始 Dialogue Pilot
- [x] `release-readiness-roadmap.md``DEC-001``DEC-003` 已确认Windows、Android、iOS以及 `en``zh-CN``ja``ko``vi-VN`
- [ ] `UI-001` UI Inventory 至少完成 Dialogue Screen。
- [ ] `UI-002` 有一版可用的 Color/Type/Spacing/Shape Token。
- [ ] 选定一张现有 Dialogue Mockup 作为 Reference。
- [ ] 明确 Pilot 的性能预算,并将 Windows、Android、iOS 横屏与 Safe Area 写入 Asset Contract。
- [ ] 先建立复制的测试 Prefab/Scene不直接覆盖生产资源。
满足后,可以直接让 Codex 执行:
> “按照 `docs/ai-assisted-ui-art-workflow.md`,为 Dialogue Pilot 创建 Asset Contract并使用现有 Dialogue Mockup 生成 `UI-DIALOG-BG-001` 的候选图。”

View File

@@ -0,0 +1,133 @@
# Offline 内容解锁系统
> **适用项目**`ichni Official`
> **状态**Core-003 已完成并经 Unity 运行时测试通过
> **最后更新**2026-07-18
本文是章节、歌曲和未来内容使用 Key 解锁机制的唯一使用说明。修改解锁规则、编写 Yarn 解锁命令或排查“内容为什么锁定”时,应先阅读本文。
## 1. 目标与边界
首发版本为纯 Offline。内容解锁记录在玩家本地 ES3 存档中,用于控制章节和歌曲是否可进入;它不是付费凭证、云端权益或反作弊机制。
解锁状态独立于下列数据域:
- 歌曲成绩Accuracy、Max Combo、FC/AP、Chart Revision。
- 剧情记录:故事树 Block、对话选项、Yarn 变量。
- 选曲缓存:本次运行中每章节最后选中的歌曲和难度。
当前不实现 Payment Unlock。未来若接入商店、DLC 或在线 entitlement应由对应模块向本系统授予同样的 Key不得在 UI 或歌曲数据中重新建立支付专用判断。
## 2. 主要代码与职责
| 位置 | 职责 |
|---|---|
| `Assets/Scripts/Saving/UnlockSaveModule.cs` | Key 存档、Schema、规则求值、章节/歌曲统一授权。 |
| `Assets/Scripts/Saving/GameSaveManager.cs` | 启动时创建并加载 `UnlockSaveModule`。 |
| `Assets/Scripts/Menu/ChapterSelection/ChapterSelectionUnit.cs` | 为章节和歌曲配置 `UnlockRequirement`。 |
| `Assets/Scripts/NewStorySystem/YarnFunctions/StoryTreeCommands.cs` | 提供 `grant_unlock` 与兼容的 `unlock_song` Yarn 命令。 |
| `Assets/Scripts/UI/ChapterSelection/ChapterSelectionUI.cs` | 阻止锁定章节进入剧情和选曲。 |
| `Assets/Scripts/UI/SongSelection/PlaySongUI.cs``SongSelectionTab.cs` | 阻止标准 Play 与快速点击绕过锁定。 |
## 3. Key 命名规则
Key 是稳定的内部 ID不是玩家可见文本也不是歌曲标题、章节标题或 Yarn 节点标题。
- 只能包含小写英文字母、数字和下划线。
- 必须以小写字母开头,长度为 196。
- 推荐格式:`来源_章节_事件_状态`
- 示例:`story_ch0_prologue_completed``story_ch0_route_a_completed``chapter_ch1_available`
- 禁止使用点号、空格、连字符、中文/日文等本地化文本,或会频繁更名的显示名称。
不符合规则的 Key 无法被授予;运行时遇到配置错误时会保持锁定并只输出一次警告,避免错误配置意外开放内容。
## 4. 配置章节与歌曲
`ChapterSelectionUnit.unlockRequirement` 控制该章节的剧情入口和选曲入口。`SongItemData.unlockRequirement` 控制歌曲自身。
根节点为空时表示无条件开放。需要锁定时,在 Odin Inspector 的 `Unlock Requirement` 中选择下列节点:
| 节点 | 含义 | 使用示例 |
|---|---|---|
| `Key` | 玩家必须持有该 Key。 | 一首歌曲要求 `story_ch0_prologue_completed`。 |
| `All Of (AND)` | 所有子条件都满足才开放。 | 同时完成两个剧情分支。 |
| `Any Of (OR)` | 满足任意一个子条件即可开放。 | 完成路线 A 或路线 B。 |
真正开始歌曲时,章节规则和歌曲规则必须同时满足。即使歌曲本身无条件开放,只要所属章节锁定,仍不能进入。
`Key`、空的 `All Of` / `Any Of` 列表、或组合中的空子节点都被视为错误配置并失败关闭。
## 5. 从 Yarn 授予 Key
### 通用内容解锁
```yarn
<<grant_unlock story_ch0_prologue_completed>>
```
`grant_unlock` 立即写入本地存档,适用于章节、歌曲、教程和未来任意内容。它本身不显示提示;若需要文案,应在 Yarn 中额外使用 `show_message`
### 兼容的歌曲命令
```yarn
<<unlock_song story_ch0_song_02_available>>
```
`unlock_song` 同样授予 Key并在首次授予后保留旧有歌曲解锁提示行为。当前提示仍会显示英文和内部 Key此显示问题属于后续本地化任务不影响授权结果。
两个命令都具备幂等性:已拥有同一 Key 时不会重复保存或重复弹出歌曲解锁提示。
## 6. 存档、Schema 与清档
- 文件:`Application.persistentDataPath/GameSaves/UnlockKeys.json`
- ES3 数据 Key`UnlockKeys`
- 当前 SchemaUnlock Save v1
本系统保留了旧 `UnlockKeys.json` 的文件名与 ES3 Key。此前仅保存 `HashSet<string>`、但没有 Schema 的预发布文件会作为 v0 无损读取,并补写为 v1文件中不符合当前命名规则的 Key 会被删除。
若读取到非 v1、且不是旧 v0 的 Schema当前预发布策略会重置该文件。正式发布后若变更解锁存档结构必须编写显式迁移不能继续删档。
`StoryManager.ClearAllStorySave()` 会同时清空剧情树、Yarn 变量和全部内容解锁 Key便于测试完整剧情进度。它不会清除歌曲成绩。
## 7. 入口防护
所有现有可进入内容的入口均需遵守同一授权规则:
| 入口 | 防护行为 |
|---|---|
| 章节剧情入口 | 按钮禁用,并在点击回调中再次检查章节规则。 |
| 章节选曲入口 | 按钮禁用,并在点击回调中再次检查章节规则。 |
| 歌曲标准 Play | 通过 `UnlockSaveModule.CanEnterSong(...)` 作最终检查。 |
| 歌曲快速点击 | 使用同一最终检查,不能绕过标准 Play。 |
`SongSelectionTab.isLocked` 只用于锁图标和预览表现,不能作为安全判断的唯一来源。剧情刚授予 Key 或 UI 被其他逻辑刷新后,真正进入前仍会重新计算规则。
## 8. 内容作者工作流
1. 先定义需要代表的进度事实,并按规则起一个稳定 Key。
2. 在 Chapter 或 Song 的 `Unlock Requirement` 中引用这个 Key 或组合规则。
3. 在对应 Yarn 节点完成时添加 `grant_unlock` 或兼容的 `unlock_song`
4. 使用新档测试锁定状态,再完成一次剧情测试授予后的即时状态。
5. 重启游戏确认 Key 仍存在;清空剧情存档后确认内容重新锁定。
不要为了“解锁某首歌”而直接修改 UI、`isLocked``UnlockKeys.json`;所有授予必须经由 `UnlockSaveModule.GrantKey(...)` 或 Yarn 命令。
## 9. 未来扩展原则
- 新内容类型优先复用 `UnlockRequirement``UnlockSaveModule`
- 需要更复杂的组合时在现有规则树中增加节点,不要在各页面复制 if 判断。
- 商店、DLC、成就或云端 entitlement 将来只负责授予/撤销 Key章节和歌曲 UI 不应关心 Key 的来源。
- 如需玩家可见的“为何锁定”说明,应添加本地化提示 Key不要展示内部 Unlock Key。
- `UnlockSaveModule.UnlockStateChanged` 预留给未来需要在当前页面即时刷新解锁状态的 UI。
## 10. 回归测试清单
1. 无规则的章节和歌曲在新档可进入。
2. 配置 `Key` 后,新档中章节/歌曲锁定。
3. 锁定歌曲的标准 Play 和快速点击均无法进入。
4. 锁定章节的剧情入口和选曲入口均无法进入。
5. `grant_unlock` 后规则立即满足;返回菜单后显示正确。
6. 重启后 Key 仍存在。
7. `All Of` 只有全部 Key 存在时开放;`Any Of` 任一 Key 存在时开放。
8. 空 Key 或错误组合不会开放内容,并只产生一次可定位警告。
9. `ClearAllStorySave()` 后剧情进度与解锁 Key 均清除,歌曲成绩保留。

View File

@@ -0,0 +1,330 @@
# ichni Release Readiness Roadmap
> 文档状态Active
> 首次基线2026-07-18
> 最近扫描2026-07-18
> 最近 Scope 更新2026-07-18
> 当前阶段Production研发中期
> 当前结论NOT READY FOR RELEASE
> 主工作范围:`D:\Projects\ichni Official`
> 条件性关联:仅当任务实际修改共享序列化、内容导出/导入或节奏游戏核心数据契约时,再纳入 `D:\Projects\IchniCreatorStudio`
## 1. 文档用途
这是 ichni 从当前研发中期走到可发布版本的长期执行文档。它同时承担四个职责:
1. 保存当前项目基线,避免后续只凭印象判断进度。
2. 定义 Release 的完成标准和阶段门。
3. 用稳定的任务编号逐项推进、复核和留证。
4. 记录需要跨项目处理时的明确依赖;本轮默认只处理 `ichni Official`
本文件中的百分比是“发布就绪度区间”,不是工时完成率,也不能直接用于推算发布日期。每项任务只有在验收证据可复查时才能标记为完成。
## 2. 已确认的 Release Scope
本节已由产品负责人于 2026-07-18 确认。路线图从此按下列范围执行Chapter 1 和 Creator 都不能阻塞 Chapter 0 首发。
- [x] `DEC-001` 首发平台PCWindows、Android、iOS。
- [x] `DEC-002` 首发内容Chapter 0 是最低且必须完成的首发内容Chapter 1 为 Stretch Goal只能在不危及 Chapter 0 的前提下推进。
- [x] `DEC-003` 首发语言:`en``zh-CN``ja``ko``vi-VN`
- [ ] `DEC-004` 发布渠道:尚未确定;在 Gate 3 前必须决定具体 PC 与移动端商店。
- [x] `DEC-005` 首发模式:纯 Offline账户、登录、联网服务均不属于首发功能。
- [x] `DEC-006` 目标日期:暂无固定日期;原则是 Chapter 0 达到质量门后尽早发布,而不是用未确定的谱面工期反推日期。
- [x] `DEC-007` 工作重心:当前只计划/美术/游戏框架/剧情/本地化/设置/发布准备Chapter 0 谱面流程已稳定,由独立节奏游戏制作链路自行推进并只提供完成状态。
记录格式:
| Decision | 选择 | 决策日期 | 决策人 | 影响 |
|---|---|---|---|---|
| DEC-001 | Windows + Android + iOS | 2026-07-18 | 产品负责人 | 三平台 Build、QA、Input、Safe Area 与商店合规 |
| DEC-002 | Chapter 0 必达Chapter 1 Stretch | 2026-07-18 | 产品负责人 | Chapter 1 不得阻塞内容锁定 |
| DEC-003 | en / zh-CN / ja / ko / vi-VN | 2026-07-18 | 产品负责人 | 五语翻译、字体、排版和 LQA |
| DEC-004 | TBD | — | 产品负责人 | 商店 SDK、签名、年龄分级、隐私和商店材料 |
| DEC-005 | Pure Offline | 2026-07-18 | 产品负责人 | 移除/Feature Gate 登录与网络依赖 |
| DEC-006 | 无固定日期,尽早完成 | 2026-07-18 | 产品负责人 | 用 Gate 和质量证据管理,不承诺虚假日期 |
| DEC-007 | 非谱面工作优先;谱面由独立流程跟踪 | 2026-07-18 | 产品负责人 | 路线图不展开 Creator 或谱面生产排期 |
## 3. 现状扫描结论
### 3.1 阶段判断
项目处于明确的 **Production** 阶段,置信度高:核心音游 Runtime、两个主要 Scene、内容加载、谱面制作器、Wwise、章节/选曲/演奏/结算等系统已经存在,且已有可运行内容。项目尚未进入 Feature Complete、Content Complete 或 Release Candidate 阶段,因为主 GameLoop 的结果持久化、剧情节点、本地化、设置完整性、测试、Build Pipeline 和发布合规仍有阻断项。
### 3.2 发布就绪度快照
| 领域 | 就绪度区间 | 状态 | 当前判断 |
|---|---:|---|---|
| 核心音游 Runtime | 6075% | Yellow | 演奏、判定、暂停、结算骨架存在;记录初始化、进度写回和异常路径需补齐 |
| 谱面与章节内容 | 约 60% | Yellow | 以用户提供的 60% 为准Official 当前扫描到 13 个歌曲目录、31 组难度包 |
| GameLoop / Progression | 3045% | Red | 页面链路存在但结果未确认写回存档Story 的 Song/Tutorial 节点仍为占位 |
| UI/UX | 3550% | Yellow | 已有完整视觉方向和主要页面响应式、Safe Area、可访问性、占位文本与统一规范未完成 |
| Settings / Input | 3550% | Red | 音量、帧率、Render Scale、Offset、语言、Rebind 已有;存在逻辑缺口与移动端风险 |
| 剧情系统与文本 | 2035% | Red | Yarn/Presenter/Portrait/Save 框架存在;目前只有少量原型文本和不完整 StoryData |
| Localization | 1025% | Red | 同时使用 I2 与 Unity Localization源语言配置冲突多数 Locale 空缺 |
| Creator 内容管线 | 不纳入本轮 | Gray | 仅在 Official 出现共享数据或导入/导出关联证据时重新纳入 |
| QA / Automation | 010% | Red | 未发现项目自有自动化测试、Test asmdef、CI 或正式回归证据体系 |
| Build / Release Engineering | 515% | Red | 缺少可复现 Build Profile、CI、版本/渠道矩阵、发布候选流程和回滚方案 |
| Legal / Store / Operations | 010% | Red | 未发现隐私政策、EULA、Credits、第三方许可台账、商店素材清单或上线运维手册 |
### 3.3 已确认的工程与内容资产
- `ichni Official` 使用 Unity `6000.3.7f1`Creator 的同版本信息仅作为条件性关联基线保存。
- Official Build Settings 当前包含 `Assets/Scenes/MenuScene.unity``Assets/Scenes/GameScene.unity`
- Official 的用户代码规模已经足以支撑完整产品,不建议推倒重写;应以修复闭环、统一数据与建立验证体系为主。
- Official 当前发现 13 个歌曲目录和 31 组完整加密谱面包,每组含 `Beatmap``ProjectInfo``SongInfo``CommandScripts`
- Creator 当前发现 15 个项目目录和 16 组对应 JSON 内容;这是基线信息,不是本轮工作范围。只有当 Official 的首发内容出现共享数据/导出异常时,才建立跨项目 Manifest 或处理 Creator。
- UI 已有统一的深蓝/青色、轨道与装饰线条风格,适合渐进式重构,不需要先更换全部视觉语言。
- 新 Story 系统已具备 Yarn 播放、Typewriter、Choice、Portrait、Variable Save 等能力,重点是完成内容、数据和 GameLoop 接入。
## 4. 需要优先解决的 Release Blockers
### P0阻止形成完整产品闭环
1. **演奏结果初始化和存档闭环待 Unity 端到端验证。** 2026-07-18 已在 `GameManager` 初始化 `PlayingRecorder`,并在 Wwise 歌曲结束回调中将结果写入 `BeatmapSave` / `SongStatusSave`;需要验证结算、退出、重开后的 Accuracy / FC / AP 和完成状态一致。
2. **Story 到 Song/Tutorial 的转场仍是占位。** `SongBlockView``TutorialBlockView` 只输出 `Debug.Log`
3. **Chapter 0 StoryData 不完整。** 当前定义了 `A-0``B-0``B-1``C-0`,只有 `A-0` 绑定 Yarn条件中引用了未定义的 `B-2`
4. **Localization 源语言与内容不一致。** Yarn Project 的 Base Language 是 `en`,但当前 `en` Story Table 中实际是中文;`zh-CN` 仅有少量空项,其他 Locale 大多为空。
5. **Offline 首发必须完全关闭 Online/Login 路径。** TapTap 初始化被禁用Start 页面绕过登录API 指向 `http://localhost:53734`,并存在硬编码凭据、敏感响应日志和本地 Token 存储风险。首发应移除或明确 Feature Gate而非让不可用服务残留在用户路径上。
### P1阻止 Feature Complete / Beta
1. Offline 内容解锁已统一为独立 `UnlockSaveModule`;仍需补齐新档、授予 Key、重启读取与所有入口拦截的 Unity 端到端证据。
2. Settings 加载未应用语言I2 与 Unity Localization 依赖相同 Index 顺序,容易错配。
3. Rebind 使用 `Rebinds` 保存,但 Reset 查询/删除 `Rebind`,无法正确恢复默认值。
4. `KeyRebindButton` 在找不到 Action 的异常路径中可能不恢复 Input 与 Waiting Cover。
5. Input Actions 缺少完整的 Submit/Back/Controller 导航与 Control Scheme未发现 `EnhancedTouchSupport.Enable()`,移动端触控需实机验证。
6. UI Scene 内混用 `1920×1080``2560×1440` 和 Constant Pixel Size未发现 `Screen.safeArea` 适配。
7. Scene 中仍存在大量测试值、硬编码中英文、`114514``Choice 0`、Test 文案等候选占位内容。
8. Localization 资产不完整I2 54 个 Term 中多个语言缺失,且有 5 个引用 Term 与资源命名不一致Unity UI Table 只有 7 个 Key`en`/`zh-CN` 外其余表为空Message Table 为空。
9. `StreamingAssets` 同时包含 Android、iOS、Windows64 ThemeBundle可能让各平台 Build 携带无关资源。
10. Runtime `Assets` 中保存了大量 PSD、整屏 Mockup 和 120 帧 Loading PNG需在不破坏引用的前提下分离 Source Art 与 Runtime Export。
### 条件性跨项目事项(不进入当前执行队列)
- Creator 的静态构建曾报 3 个 `PositionSync` 相关错误。这是 Creator 自身的健康问题,但当前 UI、剧情、设置、Offline GameLoop 和首发准备不依赖它;除非 Official 的 Chapter 0 导入/读取出现明确关联,本轮不处理。
- 未来只要任务修改共享 `BM`、加密/序列化 Schema、Beatmap Export Contract 或 `BaseElement` 节奏游戏元素,就必须先重新评估 Official/Creator 同步范围,并在任务说明中明确提醒。
### P2阻止 Release Candidate / 长期维护
1. 未发现项目自有自动化测试、CI、稳定的 Build Profile 和可追踪测试证据。
2. 未建立 Crash Reporting、性能基线、最低设备矩阵、长时间 Soak Test 和存档兼容测试。
3. 未建立隐私政策、EULA、Credits、第三方 SDK/字体/音乐/素材许可台账。
4. PlayerSettings 中 Standalone Application Identifier 仍是 Unity Template 值;版本、渠道、签名和商店资料未形成单一来源。
5. 代码中仍有 14 处 `NotImplementedException`、158 处 `Debug.Log` 和少量 TODO需按 Runtime 可达性审计,不能仅机械删除。
6. Summary 的 Share Button 存在但未发现实现;需要实现或移除。
## 5. Release Definition of Done
ichni 只有同时满足以下条件,才可以进入正式 Release
- [ ] 产品 Scope、平台、语言、渠道与 Online 范围已经冻结并记录。
- [ ] 新用户可以从启动页进入章节、完成剧情/选曲、完成歌曲、查看结算、保存进度、退出并重开继续。
- [ ] Chapter 0 的首发歌曲、谱面、剧情、教程、音频和 UI 内容完成并锁定Chapter 1 仅在不影响该 Gate 时纳入。
- [ ] 不存在可达的占位节点、测试按钮、测试文本、开发后门或默认服务地址。
- [ ] `en``zh-CN``ja``ko``vi-VN` 达到 100% Key 覆盖,完成字体、溢出、断行和真机 LQA。
- [ ] Settings 在所有目标平台可保存、迁移、重置并实际生效Debug Settings 在 Release Build 不可访问。
- [ ] 键鼠、手柄和目标移动设备的 Input 路径通过验证;所有移动平台通过 Safe Area 测试。
- [ ] 如首发工作实际触及共享 Schema、序列化或导出/导入契约,则 Official 与 Creator 的相关面已完成同步与回放验证;否则无需作为首发 Gate。
- [ ] 每个首发 Build 可由干净环境按文档重复构建并产出版本、Hash、符号和变更记录。
- [ ] P0/P1 Bug 为 0获准延期的 P2 有 Owner、风险说明和后续版本计划。
- [ ] 核心流程自动化测试、人工回归、性能、Soak、存档升级和崩溃恢复均有可复查证据。
- [ ] 商店素材、年龄分级、隐私、EULA、Credits、许可、SDK 声明和联系方式准备完成。
- [ ] Release Candidate 在目标设备矩阵上通过最终签署,并已演练回滚/Hotfix 流程。
## 6. 阶段路线图与 Gate
本路线图采用 Gate而不是先虚构日期。平台、内容、语言、Offline 和工作重心已经冻结;仅在 Gate 3 前补充商店渠道决策与对应日历排期。谱面制作不作为本路线图的排期驱动项。
### Gate 0 — Scope Baseline
目标:把“什么叫首发完成”冻结成可执行合同。
交付物:
- 已确认的 `DEC-001``DEC-003``DEC-005``DEC-007` 录入本文;在 Gate 3 前确认 `DEC-004`
- Chapter 0 Release ManifestSong、Difficulty、Story Node、Tutorial、Locale、PlatformChapter 1 单独标记为 Stretch。
- Offline 决策落实为登录/网络功能的 Build-time 或 Runtime Feature Gate。
- 首发设备矩阵、性能预算和 Release Definition of Done 复核。
Exit Criteria所有后续任务都能判断“首发必须 / 可延期 / 不做”,且没有未归属的 Release Scope。
### Gate 1 — Complete Playable Loop
目标:先让一个 Chapter 0 样本形成可靠闭环,再扩大内容生产。
必须完成:`CORE-001``CORE-008``STORY-001``SET-001``QA-001`
Exit Criteria新存档从启动到完成一首歌、结算、解锁、返回、退出并重开后数据一致失败/取消/重试也不会损坏存档。
### Gate 2 — Feature Complete Alpha
目标Chapter 0 的所有首发功能都有最终实现路径不再新增大功能Chapter 1 只作为独立 Stretch 轨道推进。
必须完成Story、Settings、Input、UI 基础规范、Offline Feature Gate所有可达占位实现清零或明确剔除。Creator 不在本 Gate 内,除非实际改动共享内容契约。
Exit Criteria所有首发功能都可用可以缺内容和细节 Polish但不能存在“以后再接”的功能节点。
### Gate 3 — Content Complete Beta
目标:内容锁定,进入系统性修复和质量验证。
必须完成Chapter 0 首发谱面状态确认、剧情、五语翻译、音频、UI Export 和教程;完成 Release Manifest 对账。
Exit Criteria除 Bug Fix、性能、LQA 和批准的微调外,不再改数据 Schema、核心流程或新增文本。
### Gate 4 — Release Candidate
目标:构建一个可直接发布、仅等待签署的候选版本。
必须完成:自动化/人工回归、平台认证检查、性能、Soak、存档升级、安装/卸载、Offline 启动与离线可玩验证、Legal/Store、Build Reproducibility。
Exit CriteriaP0/P1 为 0候选包 Hash 固定;所有签署证据齐全;回滚和 Hotfix 已演练。
### Gate 5 — Release & Stabilization
目标:安全上线并监控第一轮真实用户问题。
交付物发布包、版本说明、支持渠道、Crash/日志观察、Known Issues、Day-One Patch 判断、Postmortem 数据。
Exit Criteria首发观察窗口结束严重问题关闭或已部署修复进入正常版本节奏。
## 7. 可逐项执行的 Master Backlog
状态只能使用:`TODO``IN PROGRESS``BLOCKED``VERIFY``DONE``DEFERRED``EXTERNAL``EXTERNAL` 表示由独立节奏游戏制作流程跟踪但仍受 Release Gate 验证;`DONE` 必须填写 Evidence。
| ID | Priority | 项目 | 工作项 | Size | Dependency | Status | Evidence |
|---|---|---|---|---|---|---|---|
| REL-001 | P0 | Official | 确认平台、渠道、内容、语言、Online 和日期 Scope | S | — | IN PROGRESS | DEC-001/2/3/5/6/7 已于本文第 2 节确认DEC-004 待定 |
| REL-002 | P0 | Official | 建立 Chapter 0 Release Manifest 与唯一内容 IDChapter 1 单独标为 Stretch | M | REL-001 | TODO | Manifest + 对账报告 |
| REL-003 | P0 | Official | 定义 Release DoD、性能预算和目标设备矩阵 | S | REL-001 | TODO | 本文复核 + 设备表 |
| CORE-001 | P0 | Official | 创建 `PlayingRecorder` 后调用并验证 `Initialize()` | S | — | DONE | 2026-07-18已通过完整游玩流程与重启读取验证。 |
| CORE-002 | P0 | Official | 结算时写回最高 Accuracy、FC/AP、完成状态与持久化当前项目尚未定义 Score 规则 | L | CORE-001 | DONE | 2026-07-18已验证 ES3 写入、重启读取与结果合并。 |
| SAVE-001 | P1 | Official | 游戏记录 Schema Version、旧存档迁移前备份、未来版本只读保护 | M | CORE-002 | DONE | 2026-07-18当前预发布策略为 Schema v1 不兼容存档重置;正式发布前须恢复迁移/保护策略。 |
| SAVE-002 | P1 | Official | 每谱面 Chart Revision 与历史 Max ComboRevision 变化仅重置该谱面成绩 | M | CORE-002 | DONE | 2026-07-18已验证 Revision 变化与 Max Combo 合并行为。 |
| UI-008 | P1 | Official | 保持章节内存选曲/难度缓存:恢复退出歌曲和难度,不写入玩家存档 | S | CORE-002 | DONE | 2026-07-18已验证失效歌曲、不可用难度与空配置的安全回退。 |
| CORE-003 | P0 | Official | 明确纯 Offline 下的 Story/Song/Payment Unlock 行为;无首发用途的 Payment Unlock 必须移除或可靠禁用 | M | REL-001 | DONE | 2026-07-18已验证独立 Unlock Save v1、章节/歌曲统一规则、Yarn grant_unlock、重启读取和所有现有进歌入口拦截Payment Unlock 运行时代码已移除。 |
| CORE-004 | P0 | Official | 实现 `SongBlockView` 到歌曲加载/返回 Story 的流程 | M | REL-002 | TODO | PlayMode + Manual E2E |
| CORE-005 | P0 | Official | 实现 `TutorialBlockView` 或从首发 Scope 移除 | M | REL-001 | TODO | Tutorial E2E / Scope Decision |
| CORE-006 | P0 | Official | 为 Project/Theme/Bundle/Beatmap 加载增加错误、重试、取消和平台失败处理 | L | — | TODO | Fault-injection Checklist |
| CORE-007 | P1 | Official | 实现或移除 Summary Share Button | S | REL-001 | TODO | UI Test |
| CORE-008 | P1 | Official | 清理 `ProjectLoader.TestLoad()` 命名与开发假设,形成正式入口 | S | CORE-006 | TODO | Code Review |
| STORY-001 | P0 | Official | 修复 Chapter 0 Story Graph未定义 `B-2`、空绑定与条件完整性 | M | REL-002 | TODO | Graph Validator |
| STORY-002 | P0 | Official | 决定 Yarn 真正 Source Language 并修正 Yarn Project/Table | M | DEC-003 | TODO | Locale Contract |
| STORY-003 | P0 | Official | 完成首发剧情、角色表、Portrait、Command 与分支条件 | L | REL-002, STORY-002 | TODO | Story Content Audit |
| STORY-004 | P1 | Official | 移除 `Test Title` 等原型命令,补充缺失内容验证器 | M | STORY-003 | TODO | Zero-placeholder Report |
| LOC-001 | P0 | Official | 选择 I2/Unity Localization 的职责边界或迁移方案,禁止同 Index 隐式绑定 | L | STORY-002 | TODO | Localization ADR |
| LOC-002 | P0 | Official | 建立单一 Key Manifest、术语表、Source/Target Locale 规则 | M | LOC-001 | TODO | Key Manifest |
| LOC-003 | P0 | Official | 修复 5 个缺失 I2 Term 引用和现有空翻译 | S | LOC-002 | TODO | Automated Coverage Report |
| LOC-004 | P0 | Official | 完成首发语言 100% Key 覆盖并锁定文本 | L | DEC-003, LOC-002 | TODO | Locale Coverage = 100% |
| LOC-005 | P1 | Official | 配置 TMP Font/Fallback 并完成溢出、断行、RTL如适用和 LQA | L | LOC-004 | TODO | Screenshot Matrix |
| SET-001 | P0 | Official | 修复 `Rebinds` / `Rebind` Reset Key 错配 | S | — | TODO | Automated Save Test |
| SET-002 | P0 | Official | Settings Load 时应用语言,并验证 Locale 顺序不再隐式耦合 | M | LOC-001 | TODO | Restart Test |
| SET-003 | P1 | Official | 修复 Rebind 异常退出,补 Submit/Back/Controller/Control Scheme | M | — | TODO | Input Matrix |
| SET-004 | P1 | Official | 移动端启用/验证 Enhanced Touch、触控取消与多点触控 | M | DEC-001 | TODO | Device Test |
| SET-005 | P1 | Official | 增加 Settings Version、Validation、Migration、Atomic Save 与 Reset All | L | — | TODO | Migration Tests |
| SET-006 | P1 | Official | 将 Debug/Judge/AutoPlay 从 Release Settings 隔离 | S | — | TODO | Release Build Inspection |
| SET-007 | P1 | Official | 明确 Resolution/Render Scale/Fullscreen/VSync/Frame Limit 的平台行为 | M | DEC-001 | TODO | Platform Settings Matrix |
| UI-001 | P0 | Official | 建立 UI InventoryScreen、Prefab、State、Text Key、Owner、完成度 | M | REL-001 | TODO | UI Inventory |
| UI-002 | P1 | Official | 建立 UI Design TokensColor、Type、Spacing、Border、Motion、Icon | M | UI-001 | TODO | UI Style Guide |
| UI-003 | P1 | Official | 统一 Canvas Scaler 策略并实现 Safe Area | L | DEC-001, UI-002 | TODO | Resolution Screenshot Matrix |
| UI-004 | P1 | Official | 清理 Scene 中测试/硬编码文本并全部接入 Localization | L | LOC-002 | TODO | Static Scan + Runtime Review |
| UI-005 | P1 | Official | 补齐 Focus、Keyboard/Controller Navigation、文字缩放与色彩对比 | L | UI-002, SET-003 | TODO | Accessibility Checklist |
| UI-006 | P1 | Official | 按 `ai-assisted-ui-art-workflow.md` 完成一个 Pilot Screen | M | UI-002 | TODO | Pilot A/B + Unity Capture |
| UI-007 | P2 | Official | 审核并迁移 PSD/整屏 Mockup只保留 Runtime Export 在 `Assets` | L | UI-001 | TODO | Reference Audit + Build Size Diff |
| CONTENT-001 | P2 | Creator条件性 | 仅当 Official 出现共享数据/导出异常时,建立 Creator Source → Export → Official Package 对账 | M | REL-002 | DEFERRED | 关联问题的 Roundtrip Report |
| CONTENT-002 | P2 | Creator条件性 | 修复/确认 3 个 `PositionSync` 静态编译错误 | M | — | DEFERRED | 仅在 Creator 成为当前阻塞项时执行 |
| CONTENT-003 | P0 | Official外部跟踪 | Chapter 0 谱面完成状态与逐谱面 Schema、Timing、Audio、Difficulty 验证 | L | REL-002 | EXTERNAL | Beatmap QA Sheets / 完成状态 |
| CONTENT-004 | P1 | Official | 审核 Wwise Event/Bank、缺失音频、平台导入与音量分类 | L | REL-002 | TODO | Wwise Validation |
| CONTENT-005 | P1 | Official | 按目标平台只打包对应 ThemeBundle移除跨平台冗余 | M | DEC-001 | TODO | Build Size Report |
| QA-001 | P0 | Official | 建立最小 EditMode/PlayMode Test asmdef 和核心流程 Smoke Test | L | — | TODO | Test Results XML |
| QA-002 | P1 | Official | 为存档升级、Story Graph、Localization 和 Chapter 0 Runtime Data 写自动检查;共享导出仅在需要时纳入 | L | QA-001 | TODO | CI Test Results |
| QA-003 | P1 | Official | 建立 Bug 模板、Severity/Priority 和每 Gate 的回归清单 | M | — | TODO | QA Docs |
| QA-004 | P1 | Official | 建立 CPU/GPU/Memory/Loading/Build Size 基线和最低设备预算 | L | DEC-001 | TODO | Profiler Captures |
| QA-005 | P1 | Official | 执行 2h/8h Soak、暂停恢复、来电/切后台、无网络环境启动/游玩和存档破坏测试 | L | Gate 3 | TODO | Soak Logs |
| BUILD-001 | P0 | Official | 建立可复现的 Development/Release Build Profile 与版本来源 | L | DEC-001 | TODO | Clean Build Record |
| BUILD-002 | P1 | Official | 建立 CICompile、Tests、Content Validators、Build Artifact | L | BUILD-001, QA-001 | TODO | CI Run URL/Log |
| BUILD-003 | P1 | Official | 修正 Application Identifier、Signing、Scripting Backend 和平台设置 | M | DEC-001, DEC-004 | TODO | PlayerSettings Audit |
| BUILD-004 | P1 | Official | 建立 Crash Symbol、日志、Crash Reporting 与隐私约束 | M | DEC-004 | TODO | Staging Crash Test |
| ONLINE-001 | P0 | Official | 将纯 Offline 决策落实:完全剔除或可靠 Feature Gate 登录、TapTap、网络入口和 Localhost 配置 | M | DEC-005 | VERIFY | 2026-07-18玩家路径已绕过并隐藏登录界面Release Build 无网络 E2E 待补 |
| ONLINE-002 | P2 | Official | 为未来 Online 版本建立 HTTPS、Server URL、Secret、Token 安全改造设计 | L | ONLINE-001 | DEFERRED | Security ADR |
| ONLINE-003 | P2 | Official | 为未来 Online 版本建立登录、断网、撤销和隐私删除测试设计 | L | ONLINE-002 | DEFERRED | Integration Test Plan |
| LEGAL-001 | P1 | Official | 建立第三方 SDK、字体、音乐、图片和代码 License/Credit 台账 | M | REL-002 | TODO | License Register |
| LEGAL-002 | P1 | Official | 准备 Offline 数据声明/Privacy Policy、EULA、Support 与年龄分级材料 | L | DEC-004, ONLINE-001 | TODO | Approved Documents |
| STORE-001 | P1 | Official | 准备商店文案、截图、Trailer、Icon、Capsule、系统需求和 Locale | L | Gate 3 | TODO | Store Preview |
| REL-004 | P0 | Official | 执行最终 Release Checklist、签署 RC 和回滚演练 | L | Gate 4 | TODO | Signed RC Record |
## 8. 推荐的首批执行顺序
不要先批量重做美术。当前最高收益顺序是:
1. 将第 2 节确认的 Scope 固化到 `REL-002` Chapter 0 Release ManifestChapter 1 只保留 Stretch 标记。
2. 执行 `STORY-001``CORE-004`,让 Chapter 0 Story 真正连接歌曲并形成可验证的主线闭环。
3. 决定并执行 `CORE-005`:接入 Tutorial Block或将其从首发 Chapter 0 Scope 移除。
4. 执行 `ONLINE-001`,从首发 Build 中彻底关闭 Login、TapTap、网络入口和 Localhost 配置。
5. 执行 `LOC-001``STORY-002`,在继续写 Chapter 0 剧情/五语翻译前确定源语言和管线。
6. 执行 `SET-001``SET-002``SET-003``SET-004`,修复 Settings/Input并优先验证 Android/iOS Touch。
7. 执行 `QA-001` 和核心 E2E Smoke Test防止后续改 UI 时破坏 GameLoop。
8. 执行 `UI-001``UI-002`,再开始 `UI-006` 的 AI Dialogue Pilot不要让 Chapter 1 美术阻塞此处。
9. 由独立谱面流程更新 `CONTENT-003` 的 Chapter 0 完成状态;本路线图只消费其 QA 证据,不安排 Creator 工作。
10. 在 Gate 2 后启动完整 Build/Store/Legal 工作;最晚在 Gate 3 前决定 `DEC-004` 商店渠道。
## 9. 验证矩阵
### Core E2E 必测路径
- Fresh Install → Start → Chapter → Story → Song → Loading → Play → Pause/Resume → Summary → Return。
- Pass / Fail / Restart / Abort / Force Close / Relaunch。
- 首次 Clear、重复 Clear、更高分、更低分、FC、AP、不同 Difficulty。
- Story Choice、章节/歌曲条件锁、Unlock Key 授予、Save Upgrade。
- 缺 ThemeBundle、损坏 Beatmap、无网络、Wwise Bank 缺失、Locale 资源缺失。
### UI 设备/分辨率最低矩阵
- 16:91920×1080、2560×1440。
- 16:101920×1200。
- Ultrawide2560×1080 或目标范围。
- Android/iOS至少各一台带刘海/挖孔和一台低端设备;横屏 Safe Area 为首发必测项。
- Keyboard/Mouse、Controller、Touch系统文字缩放和不同 Locale 长文本。
### 存档兼容
- 无存档、当前版本存档、上一发布版本存档、缺字段、损坏文件。
- Settings、Key Rebind、Story Variables、Song Progress、Unlock Keys 分别验证。
- 写入期间强制退出,验证不会同时损坏主存档与备份。
## 10. 基线证据索引
| 发现 | 证据路径 |
|---|---|
| Recorder 只创建未初始化 | `Assets/Scripts/Manager/GameManager.cs``Assets/Scripts/Manager/PlayingRecorder.cs` |
| Song Save 只发现初始化/读取,未发现结算写回 | `Assets/Scripts/Saving/GameSaveManager.cs``Assets/Scripts/UI/SongSelection/` |
| Song/Tutorial Story 节点为占位 | `Assets/Scripts/NewStorySystem/Tree/SongBlockView.cs``TutorialBlockView.cs` |
| Chapter 0 引用未定义 `B-2` | `Assets/Story/Chapter0/StoryData_Chapter0.asset` |
| Yarn 与 Story Localization 配置冲突 | `Assets/Story/Chapter0/Chapter0.yarnproject``Assets/Localization/Story/` |
| I2 Term 覆盖与命名缺口 | `Assets/Resources/I2Languages.asset` |
| Rebind Reset Key 错配 | `Assets/Scripts/UI/Settings/RebindingWindow.cs` |
| Login 被绕过、Localhost API 与 SDK 禁用 | `Assets/Scripts/UI/StartPage/StartUIPage.cs``Assets/Scripts/Online/` |
| UI 缩放策略混合 | `Assets/Scenes/MenuScene.unity``Assets/Scenes/GameScene.unity` |
| 多平台 ThemeBundle 同时位于 StreamingAssets | `Assets/StreamingAssets/ThemeBundles/` |
| Creator 编译阻断(条件性,不在当前队列) | `D:\Projects\IchniCreatorStudio\Assets\Scripts\Console\consoleOnMono.cs``Assets\Scripts\DynamicUI\Core\InspectorBuilder.cs` |
构建验证备注2026-07-18 的 Creator `dotnet build --no-restore` 报 3 个 `PositionSync` 相关错误。Official 的同类静态检查受到 `obj\Debug\Assembly-CSharp.dll` 文件锁影响,未得到可作为代码结论的结果;必须在 Unity Console 与清洁构建环境重新验证。Git/LFS clean filter 也阻止了本次可靠获取完整 Worktree 状态,因此本文不把 Git 状态作为发布证据。
## 11. 长期维护规则
1. 每周或每个 Sprint 只更新任务的 `Status``Evidence` 和“最近扫描”日期,不随意改 ID。
2. Scope 变化必须先更新 Decision再评估受影响的 Gate、测试矩阵和内容总量。
3. 只有 Official 任务实际修改共享 Schema、序列化类、导出契约或 `BaseElement` 节奏游戏元素时,才纳入 Creator并要求两边的实现和 Roundtrip Evidence。
4. `DONE` 不等于“代码写完”,而是 Acceptance Criteria 已通过且 Evidence 可复查。
5. 每个 Gate 前创建一次 SnapshotBuild Version、Commit、Content Manifest Hash、Test Results、Known Bugs。
6. 新 P0/P1 Bug 必须立即关联到 Gate不能仅记录在聊天或个人 TODO 中。
7. 进入 Release Candidate 前,再正式执行项目的 `/launch-checklist` 工作流进行全团队签署;本次扫描没有替代该最终流程。
## 12. 下一次更新入口
当前 Scope 已确认后:
1. 先建立 `REL-002` 的 Chapter 0 Release Manifest并把 Chapter 1 标为 Stretch。
2.`STORY-001``CORE-004` 开始实施 Gate 1 的下一段主线闭环。
3. 同步建立第一份 Core E2E 测试证据。
4. 在 Gate 3 前补充 `DEC-004` 的具体商店渠道、账号、签名与提交要求。

View File

@@ -0,0 +1,161 @@
# 存档、剧情进度与选曲缓存:当前状态说明
> **适用项目**`ichni Official`
> **最后更新**2026-07-18
> **状态**:已完成 Core-002 的存档与选曲缓存收尾,以及 Core-003 的统一 Offline 内容解锁模块。
本文记录当前已落地的运行时存档机制、数据边界、字段语义和维护规则。它不是面向玩家的说明;以后修改存档、谱面、剧情或选曲逻辑时,应先阅读本文。
## 1. 发布范围与基本原则
- 首发平台为 Windows、Android、iOS当前目标允许为纯 Offline 版本。
- Chapter 0 是首发最低内容线Chapter 1 以实际完成度为准。
- 首发本地化目标为英文、中文、日文、韩文、越南文。
- 游戏记录和剧情记录刻意分离:成绩变化不应破坏剧情进度,剧情变量变化也不应改写成绩。
- 当前仍处于正式发布前。因此两套存档的 Schema 均为 `v1`,出现不兼容旧测试存档时允许删除并重建;正式发布后必须改为显式迁移,不能沿用此策略。
## 2. 存档总览
| 数据域 | 主要职责 | ES3 文件 | 当前 Schema | 启动加载顺序 |
|---|---|---|---|---|
| 游戏记录 | 歌曲完成状态、每个谱面的成绩、Chart Revision | `GameSaves/SongSaves.json` | Song Save v1 | 先加载 |
| 内容解锁 | 已授予的章节/歌曲/教程等内容访问 Key | `GameSaves/UnlockKeys.json` | Unlock Save v1 | 游戏记录后、菜单显示前加载 |
| 剧情记录 | 各章节剧情树、选项状态、全局 Yarn 变量 | `StorySaves/*.json`(由 `StorySaveModule` 管理) | Story Save v1 | 游戏记录后加载 |
| 选曲缓存 | 当前运行期间各章节最后选择的歌曲与难度 | 仅内存 | 不适用 | 按需创建 |
`GameSaveManager.Start()` 先初始化 `SongSaveModule` 并加载游戏记录、剧情解锁 Key再初始化 `StorySaveModule`。菜单和章节 UI 因而可在首次展示前读取成绩和解锁状态。
## 3. 游戏记录:歌曲与谱面成绩
主要实现位于 `Assets/Scripts/Saving/GameSaveManager.cs`
### 3.1 保存时机
一次正常游玩结束后,运行时的 `PlayingRecorder` 会把该局结果交给 `SongSaveModule.RecordPlayResult(...)`。该方法负责:
1. 确认 `songName``saveDifficultyId` 和本局判定数据有效;
2. 取得或创建对应 `SongStatusSave``BeatmapSave`
3. 根据当前 `Chart Revision` 判断是否需要先重置该谱面的可比成绩;
4. 更新最高 Accuracy、最高 Max Combo以及“曾达成”的 FC/AP
5. 将修改后的完整游戏记录和 Song Save Schema 一起写回 ES3。
若本局没有任何有效判定(`totalCount <= 0`),不会生成成绩记录,以免异常退出污染数据。
### 3.2 字段与含义
| 字段 | 所属层级 | 含义与更新规则 |
|---|---|---|
| `SongStatusSave.isCompleted` | 歌曲 | 任意一个有效游玩结束后置为 `true`;不会因为较差成绩回退。 |
| `SongStatusSave.additionalInfo` | 歌曲 | 预留信息;当前保持非空字符串,未承载游戏规则。 |
| `BeatmapSave.accuracy` | 谱面 | 当前 `Chart Revision` 下的最高 Accuracy。 |
| `BeatmapSave.maxCombo` | 谱面 | 当前 `Chart Revision` 下的最高 Max Combo。 |
| `BeatmapSave.isFullCombo` | 谱面 | Sticky 标记:本 Revision 内曾 FC 即保持 `true`。 |
| `BeatmapSave.isAllPerfect` | 谱面 | Sticky 标记:本 Revision 内曾 AP 即保持 `true`。 |
| `BeatmapSave.chartRevision` | 谱面 | 成绩所对应的谱面版本;与配置不一致时仅重置该谱面的可比成绩。 |
### 3.3 稳定 ID`saveDifficultyId`
谱面成绩的字典 Key 是 `DifficultyData.saveDifficultyId`,而不是难度在 UI 列表中的位置。这样调整难度显示顺序、临时隐藏某难度或为某曲新增难度,都不会把旧成绩错误地归属到另一张谱面。
`difficultyListIndex` 只用于选曲 UI 的当前列表位置,不能用作存档 ID。每个需要保存成绩的难度应拥有非负、稳定且在同一歌曲内唯一的 `saveDifficultyId`
### 3.4 `Chart Revision`
`Chart Revision` 是谱面内容版本号,不是整个存档的版本号。
- 仅改名称、封面、UI 排序等不影响判定内容的修改:不应递增。
- 改动音符、判定时机、总物量或足以使成绩不可比的规则:应递增。
- Revision 不一致时:只清空该难度的 Accuracy、Max Combo、FC、AP歌曲完成状态、其它难度成绩、剧情存档和解锁 Key 均保留。
## 4. Schema Version
`Schema Version` 描述的是**存档数据结构**,不是游戏版本,也不是 `Chart Revision`
当前 Song Save 和 Story Save 都为 `v1`。加载到不存在 Version 或 Version 不等于当前版本的数据时,预发布策略会删除该域的旧文件并按 v1 重建。这一策略方便当前开发阶段删档验证,但正式发布后必须替换为“读取旧 Version → 逐步迁移 → 写入新 Version”的流程。
改变以下内容时通常需要升级对应 Schema
- 已持久化字段改名、删除或改变类型;
- 字典 Key 的含义改变;
- 文件或 ES3 Key 的布局改变;
- 新结构无法安全读取旧结构。
仅新增可安全默认初始化的字段时,是否升级 Schema 需按实际反序列化兼容性判断;不要为了“看起来更新了”而机械递增。
## 5. 剧情存档
剧情存档由 `Assets/Scripts/NewStorySystem/Save/StorySaveModule.cs` 负责。它独立保存章节剧情树、选项/节点状态和全局 Yarn 变量,并有自己的 Story Save Schema v1。
剧情存档不得承担歌曲 Accuracy、Combo、FC/AP 等游玩数据;反过来,游戏记录也不得复制 Yarn 变量或剧情节点状态。剧情通过 Yarn 命令授予内容解锁 Key由独立 `UnlockSaveModule` 决定章节和歌曲是否开放。
## 6. Offline 内容解锁Core-003
主要实现位于 `Assets/Scripts/Saving/UnlockSaveModule.cs`。它是第三个独立存档域:既不是歌曲成绩,也不是剧情树。文件仍使用既有 `GameSaves/UnlockKeys.json`,会把旧的无 Schema 预发布 Key 集合无损补写为 Unlock Save v1。
### 6.1 Key 命名与授予
- Key 只能使用小写英文字母、数字和下划线,必须以字母开头,长度为 196。
- 推荐按“来源_章节_事件_状态”命名例如 `story_ch0_prologue_completed`
- 不得使用点号、空格、连字符、玩家可见标题、翻译文本或会频繁修改的 Yarn 标题。
- Yarn 使用 `<<grant_unlock unlock_key>>` 授予通用 Key既有 `<<unlock_song unlock_key>>` 保持兼容,并在首次授予时继续排队歌曲提示。
### 6.2 内容规则
章节与歌曲均持有 `UnlockRequirement`。根节点为空表示无条件开放;配置了规则时可使用:
- `Key`:玩家必须持有指定 Key。
- `All Of`:所有子条件满足才开放。
- `Any Of`:任一子条件满足即可开放。
空的 `Key`、空的组合列表或空子节点属于配置错误,会保持锁定并仅在 Console 输出一次警告,避免错误配置意外放行。
真正进入歌曲时,当前章节和歌曲自身的规则必须同时满足。标准 Play、快速点击当前歌曲、以及未来的其它直达歌曲入口都必须调用 `UnlockSaveModule.CanEnterSong(...)`
首发纯 Offline 不保留 Payment Unlock 运行时代码。未来若增加商店或其它 entitlement只能向 `UnlockSaveModule` 授予 Key不能在 UI 中新增独立支付判断。
## 7. 选曲与难度缓存
选曲缓存由 `Assets/Scripts/Menu/MenuInformationRecorder.cs` 管理。
- 它只存在于内存,重启游戏后不会恢复;这是当前已确认的设计。
- 缓存单位是章节:记录该章节最后一次选择的歌曲及 `difficultyListIndex`
- 玩家重新进入同一次运行中的同一章节时UI 会优先恢复该选择。
- 若缓存歌曲已不在章节内、难度索引失效、歌曲没有可用难度,系统会安全回退,不会把空难度交给进入游戏流程。
### 6.1 跨歌曲的难度回退规则
当玩家从一首歌拖动到另一首歌,而目标歌曲没有当前难度时,系统会选择目标歌曲中“更接近”的可用难度;距离相同则优先较低的列表序号。例如当前选择难度索引为 `2`,目标歌曲只有 `0``1``3` 可用时选择 `1`
这是一项 UI 选择策略,不会改变 `saveDifficultyId` 或既有成绩归属。
## 8. 已加入的运行时防御
- 选曲初始化会处理缺失/过期缓存、空歌曲列表和无可用难度的歌曲。
- 标准 Play 按钮会在歌曲、难度、选中 Tab 缺失或歌曲锁定时拒绝进入。
- 快速进入路径已防止把空歌曲或空难度传入 `InformationTransistor`,并与标准 Play 共用 `CanEnterSong(...)` 的最终解锁检查。
- 成绩存档加载后会与当前章节/歌曲/难度定义对账:为新增歌曲和难度创建空记录,并按 Revision 检查已有记录。
- 已删除的难度记录暂不自动清除;它们不参与当前 UI 和完成度统计,保留可避免内容恢复时丢失历史成绩。
## 9. 当前已知边界与待办
1. **存档损坏处理**。尚未实现损坏文件恢复、备份或用户提示;已按当前决定延后。
2. **联网/云同步**。尚未实现;未来加入时应作为独立模块,不能直接把网络状态混入本地成绩、剧情文件或解锁 Key 文件。
3. **解锁提示本地化**。当前 `ShowUnlockMessage` 仍直接生成英文文本并显示 Key。后续本地化阶段应改为根据内容定义取得已本地化的标题与名称。
## 10. 维护与验证清单
修改相关逻辑后,至少手动验证:
1. 新档首次启动:歌曲记录、剧情记录和解锁 Key 文件能创建。
2. 完成一次谱面后退出并重启Accuracy、Max Combo、FC/AP、歌曲完成状态仍正确。
3. 用较差成绩重复游玩:最高记录和 Sticky FC/AP 不回退。
4. 提高某谱面的 `Chart Revision` 后重启:仅该难度的可比成绩清空。
5. 调整难度显示顺序后:成绩仍对应原 `saveDifficultyId`
6. 在同一运行中离开并重新进入章节:歌曲/难度恢复;目标歌曲没有同难度时按“最近、同距取低”规则回退。
7. 对无可用难度:标准 Play 与快速进入都不能开始游戏;对锁定章节或歌曲:剧情入口、选曲入口、标准 Play 和快速进入均无法绕过。
最近一次静态 C# 验证:`dotnet build Assembly-CSharp.csproj --no-restore -v:minimal /m:1 /clp:ErrorsOnly`,结果为 **0 errors**。工程现有警告未在本轮逐项审计。
## 11. 修改责任边界
本系统当前仅涉及 `ichni Official``ichniCreatorStudio` 未引用 `SongStatusSave``BeatmapSave``SongSaveModule``DifficultyData` 的这套运行时存档链路,因此本轮没有同步修改 Creator。若未来共享序列化类型、编辑器预览或导入流程明确引用这些类型再重新评估跨项目同步。

View File

@@ -0,0 +1,100 @@
# TutorialBlock 教程流程与 Chapter 0 配置
## 规则
TutorialBlock 点击后通过通用 `SelectionBox` 动态生成“游玩教程 / 跳过教程”两个选项。玩家选择任一选项的瞬间,系统都会:
1. 将 TutorialBlock 的 `tutorialProgressVariable` 写为 `true`
2. 保存全局剧情变量。
3. 将该 TutorialBlock 标记为 Completed用于故事树的节点外观和防止重复点击。
4. 重新计算所有 StoryBlock 的 `UnlockCondition`
后续 Block 必须通过 `VariableCondition` 读取教程变量解锁,不要依赖 TutorialBlock 的完成记录。选择“游玩教程”后会进入 GameScene选择“跳过教程”则留在故事树。教程游玩中退出、失败或关闭游戏不会回退已经确认的解锁状态。
## 运行时职责
| 模块 | 职责 |
|---|---|
| `StoryProgress` | 统一执行“写变量、保存、刷新故事树”;`ResolveTutorial` 同时更新教程节点完成状态。 |
| `TutorialFlowController` | 验证 TutorialBlock 配置,并临时组装教程所需的两个 `SelectionBoxOption`。 |
| `SelectionBoxUIPage` | 通用多选弹窗页面:动态生成一个 `SelectionBox`,阻断底层输入并在选择后销毁该实例。 |
| `SelectionBox` / `SelectionBoxButton` | 动态生成任意数量的选项按钮并确保一次显示只执行一个回调。 |
| `TutorialCollection` | 用 `tutorialKey` 查询教程曲目的 `SongItemData`。 |
| `InformationTransistor` | 用 `MenuReturnDestination` 保存唯一的返回目标,替代旧的两个返回 bool。 |
`MenuReturnDestination.SongSelection` 供普通选曲使用;`MenuReturnDestination.Story` 供教程使用。教程从 GameScene 返回时MenuScene 会显式重建来源章节的 StoryTree。
## Key 命名规则
所有新 Tutorial Key 和剧情变量 Key 只使用小写英文、数字和下划线:
| 用途 | Chapter 0 示例 |
|---|---|
| Tutorial Key | `chapter0_intro` |
| 教程进度变量 | `story_tutorial_chapter0_intro_resolved` |
| TutorialBlock ID建议 | `tutorial_0_intro` |
不要用显示名称、空格、点号或本地化文本作逻辑 Key。`blockId` 是 StoryTree 内部节点标识,旧内容可继续保留既有的 `A-0` 格式;新内容建议使用清晰且稳定的名称。
## 配置 Chapter 0
当前 `Assets/Story/Chapter0/StoryData_Chapter0.asset` 还没有 TutorialBlock需要在 Unity Inspector 中按以下步骤添加。
### 1. 配置教程曲目表
1. 打开 `Assets/Resources/TutorialCollection.asset`
2.`songs` 字典中将现有 Chapter 0 教程条目的 Key 调整为 `chapter0_intro`。保留其对应的 `SongItemData`,不要重新手工复制曲目数据。
3. 检查该教程条目的 `difficultyDataList`:目标难度应为 `isAvailable = true`,并确认它的 `saveDifficultyId`。当前 Chapter 0 Tutorial 的 Easy 难度应使用 ID `0`;以 Inspector 实际显示为准。
### 2. 在 StoryData 新增起始教程节点
1. 打开 `Assets/Story/Chapter0/StoryData_Chapter0.asset`
2.`blocks` 新增一个条目,或按你的章节布局将其放在第一个剧情节点之前:
| 字段 | 建议值 |
|---|---|
| `blockId` | `tutorial_0_intro` |
| `blockType` | `Tutorial` |
| `tutorialName` | 当前阶段可先填临时显示名,例如 `Chapter 0 Tutorial` |
| `tutorialKey` | `chapter0_intro` |
| `tutorialProgressVariable` | `story_tutorial_chapter0_intro_resolved` |
| `tutorialDifficultySaveId` | `0`(以教程曲目的实际 `saveDifficultyId` 为准) |
| `nextBlockIds` | 第一个后续剧情节点,例如 `A-0` |
| `unlockCondition` | 留空,使教程节点在章节开始时可点击 |
3. 为原本的第一个剧情节点 `A-0` 设置 `UnlockCondition`:选择 `VariableCondition`,并填写:
| 字段 | 值 |
|---|---|
| `variableName` | `story_tutorial_chapter0_intro_resolved` |
| `comparison` | `Equal` |
| `value` | `1` |
如果该节点还有其它前置要求,请使用 `AllOfCondition` 将原条件与上述 `VariableCondition` 组合。不要把它改成 `BlockCompletedCondition(tutorial_0_intro)`,否则会失去与 Yarn 和其它剧情变量共用条件系统的优势。
### 3. 配置通用 SelectionBox
TutorialBlock 不再需要专属弹窗。只需配置一套可供其它系统复用的 SelectionBox
1. 创建一个 `SelectionBoxButton` Prefab根节点具有 `Button``SelectionBoxButton`,子节点具有 `TMP_Text`。将 Button 和文本分别赋给 `button``labelText`
2. 创建一个 `SelectionBox` Prefab根节点具有 `CanvasGroup``SelectionBox`;配置标题 `TMP_Text`、可选内容 `TMP_Text`、选项容器 `RectTransform`,并把上一步 Prefab 赋给 `optionButtonPrefab`
3.`Assets/Scenes/MenuScene.unity` 创建一个全屏覆盖页:根节点具有 `CanvasGroup``SelectionBoxUIPage`,初始建议 `alpha = 0``interactable = false``blocksRaycasts = false`
4. 在该覆盖页下创建 `selectionBoxContainer`,并将它赋给 `SelectionBoxUIPage.selectionBoxContainer`;将上一步的 `SelectionBox` Prefab 赋给 `selectionBoxPrefab`
5. 选中 `MenuManager`,把该 `SelectionBoxUIPage` 组件拖入新的 `selectionBoxUIPage` 字段。
教程点击时会运行时生成一个 SelectionBox并生成两个按钮`游玩教程``跳过教程`。未来其它非 Yarn 的交互(例如奖励二选一、离开确认、章节分支)可以传入自己的标题、内容和 `SelectionBoxOption` 列表复用这套 UI。按钮正式本地化留待剧情文本与本地化阶段处理。
## 验证清单
1. 使用新存档或 StoryTree 的 `DebugResetChapterProgress` 重置 Chapter 0该调试重置现在也会清除本章节的教程变量。
2. 进入 Chapter 0确认只有 TutorialBlock 可点击,`A-0` 保持 Locked。
3. 点击 TutorialBlock再点击“跳过教程”节点应变为 Completed`A-0` 应立即成为 Current重进游戏后状态应保留。
4. 重置后选择“游玩教程”:确认进入 Chapter 0 Tutorial 的指定难度,且 `A-0` 在确认按钮点击后已解锁。
5. 在教程暂停页或结算页返回菜单:应回到 Chapter 0 的 StoryPage而不是 SongSelection 页面。
6. 通过普通选曲进入歌曲后返回菜单:应仍回到 SongSelection 页面,且歌曲/难度缓存不受影响。
## 配置错误的表现
以下任一配置缺失时TutorialBlock 会输出警告且不会解锁后续剧情:`tutorialKey``tutorialProgressVariable``tutorialDifficultySaveId`、TutorialCollection 中的曲目、可用的目标难度、`SelectionBoxUIPage` 引用、SelectionBox Prefab 或选项按钮 Prefab。
这是一项运行时保护;本阶段不增加导入器或 Editor 阶段的额外防呆校验。