Files
Echo/Assets/_Project/Docs/NarrationSystem_Technical_Reference.md
T
2026-07-08 20:42:51 +08:00

169 lines
7.7 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.
# NarrationSystem 技术参考
本文档定义并说明项目内的“旁白系统(NarrationSystem)”,以及它如何与任务系统(TaskSystem)配合,通过按钮继续/翻页在关键节点触发事件(例如添加/删除任务)。
相关脚本:
- `Assets/_Project/Scripts/Core/NarrationSystem/NarrationSystem.cs`
- `Assets/_Project/Scripts/Core/NarrationSystem/NarrationSequence.cs`
- `Assets/_Project/Scripts/Core/NarrationSystem/NarrationPage.cs`
- `Assets/_Project/Scripts/UI/Narration/NarrationPanelView.cs`
- (可选动作)`Assets/_Project/Scripts/Core/NarrationSystem/NarrationPlayByIdAction.cs`
任务系统动作脚本(用于旁白事件里绑定):
- `Assets/_Project/Scripts/Core/TaskSystem/Actions/AddTaskAction.cs`
- `Assets/_Project/Scripts/Core/TaskSystem/Actions/RemoveTaskAction.cs`
- `Assets/_Project/Scripts/Core/TaskSystem/Actions/SetTaskStatusAction.cs`
## 1. 设计目标
- 旁白内容以“序列(Sequence)→ 多页(Page)”组织,可在 Inspector 中动态增删页数。
- 每一页都提供事件:
- `onEnter`:进入该页时触发
- `onContinue`:玩家点击继续离开该页时触发
- 旁白系统提供统一触发入口,可被开场流程/剧情节点/触发器/互动等系统调用。
- 旁白显示时自动切换为 UI 操作模式并显示鼠标,允许玩家点击继续:
- 复用 `PlayerControlLockService.Lock/Unlock`(项目内既定范式)。
## 2. 数据结构
### 2.1 NarrationDataSO(基于 ScriptableObject 的数据容器)
脚本:`NarrationDataSO.cs`
- 在 Project 窗口右键 `Create -> Systems -> Narration -> Narration Data` 创建。
- 字段:
- `id`:序列 ID(用于按 ID 播放)
- `pages`:页列表(动态长度)
### 2.2 NarrationPageData(单页旁白数据)
脚本:位于 `NarrationDataSO.cs`
- 字段:
- `text`:该页显示的文本
- `enterActionId`:进入该页时触发的 Action ID(字符串)
- `continueActionId`:点击继续离开该页时触发的 Action ID(字符串)
### 2.3 NarrationEventListener(场景事件监听器)
脚本:`NarrationEventListener.cs`
- 用于将 `NarrationDataSO` 中的字符串 Action ID 映射到场景内的 `UnityEvent`,从而触发具体的动作(如 `AddTaskAction`)。
## 3. 核心系统
### 3.1 NarrationSystem
脚本:`NarrationSystem.cs`
Inspector 槽位:
- `Panel View`:旁白 UI 视图(`NarrationPanelView`
- `Data / Narration Database`:将所有需要支持 `PlayById``NarrationDataSO` 拖入此列表。
- `Lock Player Controls While Showing`:显示时是否锁定玩家控制并显示鼠标(推荐开启)
主要接口:
- `PlayById(string sequenceId)`:按 ID 播放序列
- `Play(NarrationDataSO sequence)`:直接播放序列引用
- `Stop()`:停止当前旁白
- `Continue()`:继续到下一页(由 UI 按钮驱动)
行为说明:
- 播放开始:显示 UI,显示鼠标(Lock),进入第 0 页并触发全局事件(带 `enterActionId`
- 点击继续:
- 先触发当前页全局事件(带 `continueActionId`
- 再进入下一页并触发新页全局事件(带 `enterActionId`
- 最后一页点击继续:结束播放,隐藏 UI,恢复控制(Unlock)
### 3.2 NarrationPanelView
脚本:`NarrationPanelView.cs`
Inspector 槽位:
- `Root`UI 根节点(用于 Show/Hide
- `Narration Text`TMP 文本控件
- `Continue Button`Reach 的 `ButtonManager`(推荐)
- `Fallback Continue Button`:如果你不用 Reach Button,可填 Unity `Button`
- `Continue Label / Finish Label`:按钮文案(继续/确认)
## 4. 与 TaskSystem 配合(在旁白页事件里加/删任务)
因为 `TaskService.AddTask(...)` 这类方法需要参数,UnityEvent 直接绑不方便,推荐通过“动作脚本”承接:
- `AddTaskAction`
- 槽位:`taskService``task``timeoutSeconds``addOrUpdate``resetStatusToTodo`
- 事件里绑定:`AddTaskAction.Invoke()`
- `RemoveTaskAction`
- 槽位:`taskService``task`
- 事件里绑定:`RemoveTaskAction.Invoke()`
- `SetTaskStatusAction`
- 槽位:`taskService``task``status`
- 事件里绑定:`SetTaskStatusAction.Invoke()`
典型用法:
- 进入第一页(onEnter):添加“寻找钥匙”任务
- 点击继续离开某页(onContinue):把“寻找钥匙”改为完成/移除
## 5. 场景搭建步骤(按顺序)
### 5.1 创建旁白系统根节点
1) Hierarchy 新建空物体:`_NarrationSystem`
2) 在 `_NarrationSystem` 上 Add Component`Core.NarrationSystem.NarrationSystem`
3) 在 `_NarrationSystem` 下新建空物体:`Sequences`
4) 将 `NarrationSystem.Sequences Root` 绑定到 `_NarrationSystem/Sequences`
### 5.2 绑定 UI
前提:你已经制作好了旁白 UI(对话框 Text + Button)。
1) 在旁白 UI 根对象上 Add Component`UI.Narration.NarrationPanelView`
2) 依次绑定槽位:
- `Root`:旁白 UI 根对象(用于开关)
- `Narration Text`:你的 TMP 文本
- `Continue Button`:你的 Reach 按钮(ButtonManager
3) 把该 `NarrationPanelView` 拖到 `_NarrationSystem/NarrationSystem.Panel View` 槽位
4) 初始建议让 UI 根对象处于隐藏(SetActive=false),由系统播放时显示
### 5.3 制作一段开场旁白(示例)
1) 在 Project 窗口右键 `Create -> Systems -> Narration -> Narration Data` 创建一个 ScriptableObject 资产,命名为 `IntroNarrationData`
2) 选中它,在 Inspector 中设置:
- `id``intro_awake`
- `pages` 添加 3 页(示例文本,可替换为你指定内容):
- 第 0 页:`你醒了。头还有些疼。`
- 第 1 页:`先四处看看,找到能离开这里的方法。`
- 第 2 页:`如果门打不开,也许需要一把钥匙。`
3) 将这个 `IntroNarrationData` 拖入 `_NarrationSystem` 上的 `Narration Database` 列表中。
### 5.4 在旁白节点绑定任务事件(示例:添加“寻找钥匙”任务)
1) 准备一个任务数据 `TaskData`:例如 `task_find_key`
2) 在 `IntroNarrationData` 的第 2 页配置:
- `continueActionId`:填入 `intro_awake_p2_continue`
3) 在场景里创建一个空物体(建议挂在 `_NarrationSystem` 下):`NarrationEventRouter`
4) 在 `NarrationEventRouter` 上 Add Component`Core.NarrationSystem.NarrationEventListener`
5) 在同物体(或子物体)上 Add Component`Core.TaskSystem.Actions.AddTaskAction`
- `Task Service`:拖场景里的 `TaskSystem(TaskService)`
- `Task`:拖 `task_find_key`
- `Add Or Update`:建议勾上(防止重复触发)
6) 回到 `NarrationEventListener`
- 添加一个 Action Mapping
- `actionId` 填入 `intro_awake_p2_continue`
- `onTrigger` 事件里拖入挂着 `AddTaskAction` 的物体,并选择 `GameAction -> Invoke()`
### 5.5 将开场动画结束点接到旁白(AwakeningSequenceController
工程已为唤醒流程增加了可绑定事件:
- `AwakeningSequenceController.onAwakeningFinished`
- `invokeFinishedWhenSkipped`(继续游戏是否也触发同一事件)
按以下步骤绑定:
1) 选中场景中负责开场唤醒动画的对象(挂了 `AwakeningSequenceController`
2) 在组件 `Events` 分组里找到 `On Awakening Finished`
3) 新建一个空物体(建议挂在 `_NarrationSystem` 下):`IntroNarrationAction`
4) 给 `IntroNarrationAction` Add Component`Core.NarrationSystem.NarrationPlayByIdAction`
- `Narration System`:拖 `_NarrationSystem (NarrationSystem)`
- `Sequence Id`:填 `intro_awake`
5) 把 `IntroNarrationAction.NarrationPlayByIdAction.Invoke()` 绑定到 `On Awakening Finished`
运行效果:
- 唤醒动画结束 → 自动弹出旁白 UI → 鼠标可点 → 点击继续翻页 → 最后一页确认后关闭 UI 并恢复控制