Files
zeling_v2/Docs/Design/52_CompletionEndingDesign.md
2026-05-08 11:04:00 +08:00

386 lines
16 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.
# 52 · 完成度与多结局设计Completion & Ending Design
> **命名空间** `BaseGames.Completion`
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
> **依赖** `BaseGames.Core.Events` · `BaseGames.Narrative`NarrativeStateMachine· `BaseGames.World`SaveManager
> **关联** 50_NarrativeDesignSystem结局门控· 14_ProgressionSystem · 32_AchievementSystem · 16_MapSystem
---
## 目录
1. [系统总览](#1-系统总览)
2. [完成度计算规则](#2-完成度计算规则)
3. [完成度显示界面](#3-完成度显示界面)
4. [NG+(新游戏+)设计](#4-ng新游戏-设计)
5. [多结局实现流程](#5-多结局实现流程)
6. [隐藏 Boss / 隐藏区域门控](#6-隐藏-boss--隐藏区域门控)
7. [收集品查看界面Codex + 收藏室)](#7-收集品查看界面codex--收藏室)
8. [完成度与成就联动](#8-完成度与成就联动)
9. [SaveData 集成](#9-savedata-集成)
10. [事件频道](#10-事件频道)
11. [编辑器友好设计](#11-编辑器友好设计)
---
## 1. 系统总览
完成度系统为 Metroidvania 品类的核心留存引擎:玩家通关后看到"68%",会被驱动去探索剩余 32%。
```
完成度系统职责:
├─ CompletionTracker → 追踪所有计入完成度的元素状态
├─ CompletionCalculator → 实时计算并缓存完成度百分比
├─ CompletionUI → 暂停菜单中的完成度概览面板
├─ NgPlusManager → NG+ 流程管理(继承哪些数据、新增哪些内容)
└─ EndingDirector → 根据完成度和叙事状态导演最终结局
```
---
## 2. 完成度计算规则
### 2.1 计入完成度的元素及权重
| 类别 | 总分 | 子元素 | 每项分值 |
|------|------|--------|---------|
| **Boss 击败** | 250 | 5 个主线 Boss × 50 | 50 / Boss |
| **房间探索** | 200 | ~100 个非 Boss 房间 × 2 | 2 / 房间 |
| **能力获取** | 100 | 10 个能力道具 × 10 | 10 / 能力 |
| **核心符文** | 80 | 16 枚核心 CharmSO × 5 | 5 / 符文 |
| **幻境碎片** | 100 | 10 个 × 10 | 10 / 碎片 |
| **Lore 道具** | 150 | ~45 件 × 约 3.3 | ≈3.3 / 件 |
| **NPC 最大好感度** | 80 | 4 个 NPC × 20 | 20 / NPC |
| **挑战房间 S 级** | 40 | 5 个挑战房间 × 8 | 8 / 挑战 |
| **全地图探索** | 0隐藏加分| 探索全部房间 | 解锁隐藏成就,不计入% |
| **合计** | **1000 分100%** | | |
**完成度百分比 = 当前总分 / 1000 × 100%**
> 分值设计约束Boss 和房间探索构成基础 45%(主线通关约达到 35~40%),收集品构成另 55%(鼓励深度探索)。
### 2.2 不计入完成度的内容
| 内容 | 原因 |
|------|------|
| 普通 NPC 对话 | 太多台词,不应成为义务 |
| 道具使用次数 | 不应要求玩家刷数值 |
| 死亡次数 | 不惩罚探索型玩家 |
| 钢铁之魂通关 | 计入独立成就,不影响主线 % |
### 2.3 CompletionTracker
```csharp
namespace BaseGames.Completion
{
public class CompletionTracker : MonoBehaviour
{
[SerializeField] CompletionConfigSO _config; // SO定义所有元素及分值
[SerializeField] WorldStateRegistry _worldState; // 叙事标志来源
[SerializeField] SaveData _saveData; // 数据来源(注入)
// 实时计算当前完成度分数(缓存,每次 SaveData 变化时更新)
public int CurrentScore { get; private set; }
public float CompletionPercent => (float)CurrentScore / _config.TotalScore * 100f;
public void RecalculateScore()
{
int score = 0;
foreach (var element in _config.Elements)
score += element.CalculateScore(_saveData, _worldState);
CurrentScore = score;
}
// 订阅所有可能影响完成度的事件频道,任意变化时重新计算
void OnEnable()
{
_onBossDefeated.OnEventRaised += _ => RecalculateScore();
_onLoreCollected.OnEventRaised += _ => RecalculateScore();
_onRoomEntered.OnEventRaised += _ => RecalculateScore();
// ... 其余事件
}
}
}
```
---
## 3. 完成度显示界面
### 3.1 暂停菜单完成度概览
暂停菜单 → "完成度" Tab 页(与任务日志并列):
```
┌─────────────────────────────────────────────────────────────┐
│ 游戏完成度 │
│ │
│ 总体进度: ████████████████░░░░░░░░░░░░░░░ 62% │
│ │
│ ▸ Boss 击败 ██████████████████████ 4 / 5 │
│ ▸ 房间探索 ████████████████░░░░░░ 78 / 100 │
│ ▸ 能力获取 ████████████████████░░ 9 / 10 │
│ ▸ 核心符文 ████████░░░░░░░░░░░░░░ 7 / 16 │
│ ▸ 幻境碎片 ████████████░░░░░░░░░░ 6 / 10 │
│ ▸ Lore 道具 ██████░░░░░░░░░░░░░░░░ 14 / 45 │
│ ▸ NPC 好感满级 ██████████░░░░░░░░░░░░ 2 / 4 │
│ ▸ 挑战房间 S 级 ████████████████░░░░░░ 3 / 5 │
│ │
│ [查看图鉴] [查看地图] │
└─────────────────────────────────────────────────────────────┘
```
- 每个类别可点击展开,显示具体哪些已完成/哪些未完成(未完成项显示"???"隐藏具体内容)
- 各类别的未完成项,仅当玩家到达该内容所在区域后才从"???"变为具体提示
- 完成度达到 80%、90%、100% 时各有一次屏幕闪光 + 成就解锁
### 3.2 通关结算画面
击败最终 Boss 后,在加载结局过场动画前,显示本次游玩的结算数据:
```
┌──────────────────────────────────────────────────────────────┐
│ 泽灵的旅程 │
│ │
│ 游玩时长 22小时 34分 │
│ 死亡次数 47 次 │
│ 总完成度 68% │
│ 结局 真实结局 · 幻境之归 │
│ │
│ [ 继续游玩(探索剩余内容) ] [ NG+ 开始 ] │
└──────────────────────────────────────────────────────────────┘
```
---
## 4. NG+(新游戏+)设计
### 4.1 NG+ 开放条件
- 任意结局通关后,在主菜单该存档槽上显示"NG+"标记
- 进入 NG+ 时,可选择继承程度(见下方)
### 4.2 NG+ 继承选项(玩家选择)
| 继承项 | 默认 | 选项说明 |
|--------|------|---------|
| 符文收集 | ✅ 继承 | 所有已获得 CharmSO |
| 能力解锁 | ✅ 继承 | 玩家已获得的运动能力 |
| 地图探索 | ✅ 继承 | 已探索的房间记录 |
| Geo 数量 | ✅ 继承 | 通关时持有的 Geo |
| 叙事进度 | ❌ 重置 | 故事节点、NPC 台词重置,但 NPC 会"认得"玩家 |
| 好感度 | 50% 继承 | 好感度减半NPC 记得玩家但需重新深交)|
| Lore 收集 | ✅ 继承 | 图鉴内容保留 |
| Boss 进程 | ❌ 重置 | Boss 重新出现,但有 NG+ 强化版行为 |
### 4.3 NG+ 专属内容
每个 NG+ 层(最多 NG+3叠加以下变化
| NG+ 层级 | 新增内容 |
|---------|---------|
| **NG+1** | Boss 新增隐藏攻击相位第3阶段敌人攻击频率 ×1.15;解锁"命魂·极限形态"符文 |
| **NG+2** | 新增隐藏 Boss 入口(幻境回廊,仅 NG+2 起可进入);所有精英怪新增强化变体外观 |
| **NG+3** | 解锁"逆位泽灵"皮肤;开放隐藏收藏室最终房间(含最后 3 件 Lore|
### 4.4 NG+ 保护规则
- NG+ 不会覆盖原存档,系统在同一槽位的 slot 内创建 `ng_plus_1` 子存档
- 玩家可在 NG+ 中随时回到原通关存档继续探索
### 4.5 NPC 对 NG+ 的特殊台词
`SaveData.ngPlusCount >= 1`,所有 NPC 初次见到玩家时会有特殊台词版本:
> 商人 MerchantA"你……以前来过这里?你的眼神像是承载过整个世界的重量。"
此版本台词通过 `DialogueVersion.requiredFlags = ["System_NgPlus"]` 实现(由 NgPlusManager 在 NG+ 开始时设置该 WorldStateFlag
---
## 5. 多结局实现流程
参见 `50_NarrativeDesignSystem.md §8`,此处补充技术实现:
### 5.1 EndingDirector
```csharp
namespace BaseGames.Completion
{
public class EndingDirector : MonoBehaviour
{
[SerializeField] EndingGate _endingGate;
[SerializeField] TimelineController _timelineController;
[SerializeField] AssetReference _normalEndingTimeline;
[SerializeField] AssetReference _trueEndingTimeline;
[SerializeField] AssetReference _hiddenEndingTimeline;
public async UniTask PlayEnding()
{
var endingType = _endingGate.EvaluateEnding();
// 记录到 SaveData
_saveData.LastEndingAchieved = endingType.ToString();
_saveData.CompletionPercent = _tracker.CompletionPercent;
// 根据结局类型加载对应 Timeline
var timelineRef = endingType switch
{
EndingType.Hidden => _hiddenEndingTimeline,
EndingType.True => _trueEndingTimeline,
_ => _normalEndingTimeline
};
var timeline = await Addressables.LoadAssetAsync<TimelineAsset>(timelineRef);
await _timelineController.PlayAndWaitAsync(timeline);
// 触发结算画面
UIManager.Instance.ShowEndingResult(endingType, _tracker.CompletionPercent);
}
}
}
```
### 5.2 结局差异说明
| 场景 | 普通结局 | 真结局 | 隐藏结局 |
|------|---------|--------|---------|
| 最终 Boss 击败动画 | 相同 | 相同 | 相同 |
| 结局过场动画时长 | ~3 分钟 | ~5 分钟 | ~7 分钟 |
| 额外旁白 | 无 | 有(泽灵内心独白)| 有(含 KnightExile 对话)|
| 片尾字幕曲目 | 标准 ED 曲 | 特别 ED 曲 | 隐藏 ED 曲(特殊编曲)|
| 结算后可解锁 | NG+ | NG+ + 特殊皮肤 | NG+ + 收藏室终章 |
---
## 6. 隐藏 Boss / 隐藏区域门控
### 6.1 隐藏 Boss幻境守卫VoidSentinel
| 属性 | 值 |
|------|---|
| 入口位置 | Ruins 区域的"幻境裂缝"(隐藏房间,需冲刺+双跳才能进入) |
| 解锁条件 | 收集 ≥ 5 个 EchoFragment + 与 ElderSage 对话 3 次以上 |
| 难度 | 显著高于同区域主线 BossT4 精英级) |
| 奖励 | EchoFragment #特殊(计入真结局计数)+ 专属符文 |
| 完成度 | 计入 Boss 类别1 个额外 Boss分值 50|
> 注:隐藏 Boss 不计入 Boss 击败类别的 5/5而是额外加分使总分上限达到 1050最终百分比上限 105% 而非 100%)。显示为"1 个额外 Boss 已击败"。
### 6.2 隐藏区域:幻境回廊
| 属性 | 值 |
|------|---|
| 开放条件 | NG+2 开始 |
| 内容 | 3 个超高难度挑战房间 + 最终 Lore 3 件 |
| 完成度贡献 | 25 分(仅 NG+2 存档计入)|
---
## 7. 收集品查看界面Codex + 收藏室)
### 7.1 Codex图鉴
详见 `50_NarrativeDesignSystem.md §6.3`。图鉴从暂停菜单入口,按区域+类型分章节显示已收集 Lore。
### 7.2 收藏室Gallery
解锁条件:完成度达到 75%。
收藏室是地图中一个真实的房间Forest 区域隐藏路径),内部墙壁随玩家收集内容逐渐出现装饰:
| 收集进度 | 收藏室变化 |
|---------|----------|
| Boss 全部击败 | 5 幅 Boss 肖像画挂上墙壁 |
| 幻境碎片 5/10 | 碎片拼图的一半出现在中央台座 |
| 幻境碎片 10/10 | 碎片拼图完整,台座发光,显示真结局入口提示 |
| Lore 全收集 | 书架填满,可阅读完整世界史 |
| NG+3 | 最后一个房间开启,包含开发者留言和彩蛋 |
---
## 8. 完成度与成就联动
| 完成度 | 成就名 | 平台成就 |
|--------|--------|---------|
| 任意结局通关 | 泽灵归来 | Steam / Switch 成就 |
| 完成度 ≥ 50% | 探索者之心 | Steam 成就 |
| 完成度 ≥ 80% | 不留遗憾 | Steam 稀有成就 |
| 完成度 = 100% | 世界已属于你 | Steam 超稀有成就(徽章)|
| 真结局 | 幻境之归 | Steam 成就 |
| 隐藏结局 | 永恒见证者 | Steam 超稀有成就 |
| NG+3 通关 | 三度轮回 | Steam 稀有成就 |
成就触发通过 `AchievementManager``IPlatformService.UnlockAchievement`,见 `32_AchievementSystem.md`
---
## 9. SaveData 集成
```csharp
public class CompletionSaveData
{
// 完成度分数快照(每次存档时更新)
[JsonProperty("completionScore")]
public int CompletionScore { get; set; } = 0;
// 最后一次通关的结局类型
[JsonProperty("lastEndingAchieved")]
public string LastEndingAchieved { get; set; } // "Normal" / "True" / "Hidden"
// NG+ 层级
[JsonProperty("ngPlusCount")]
public int NgPlusCount { get; set; } = 0;
// 各类别已完成项
[JsonProperty("defeatedBosses")]
public HashSet<string> DefeatedBosses { get; set; } = new();
[JsonProperty("exploredRooms")]
public HashSet<string> ExploredRooms { get; set; } = new();
[JsonProperty("collectedAbilities")]
public HashSet<string> CollectedAbilities { get; set; } = new();
[JsonProperty("collectedCharms")]
public HashSet<string> CollectedCharms { get; set; } = new();
[JsonProperty("echoFragmentCount")]
public int EchoFragmentCount { get; set; } = 0;
[JsonProperty("collectedLoreCount")]
public int CollectedLoreCount { get; set; } = 0;
[JsonProperty("maxAffinityNPCCount")]
public int MaxAffinityNPCCount { get; set; } = 0;
[JsonProperty("challengeRoomSCount")]
public int ChallengeRoomSCount { get; set; } = 0;
}
```
---
## 10. 事件频道
| 频道 SO | 类型 | 触发时机 |
|---------|------|---------|
| `OnCompletionScoreChanged` | `IntEventChannelSO` | 完成度分数变化(传入新分数)|
| `OnEndingAchieved` | `StringEventChannelSO` | 结局过场播放(传入结局类型字符串)|
| `OnNgPlusStarted` | `IntEventChannelSO` | NG+ 开始(传入层级)|
| `OnCodexComplete` | `VoidEventChannelSO` | 图鉴全部收集完成 |
| `OnHiddenAreaUnlocked` | `StringEventChannelSO` | 隐藏区域开放(传入 sceneAddress|
---
## 11. 编辑器友好设计
- **CompletionConfigSO** Inspector实时显示当前分值构成饼图方便调整权重
- **CompletionTracker** InspectorPlay Mode显示各类别当前分/满分、总百分比进度条
- **EndingGate** Inspector显示当前 SaveData 是否满足各结局条件(✅/❌ 清单)
- **收藏室状态 Gizmo**:在 Scene View 中显示收藏室当前解锁状态颜色(绿=已解锁、灰=未解锁)
---
*本文档版本 1.0 · 2026-04 · 关联 50_NarrativeDesignSystem / 32_AchievementSystem / 14_ProgressionSystem*