Files
Echo/Assets/_Project/Docs/NarrationSystem_Technical_Reference.md
T

169 lines
7.7 KiB
Markdown
Raw Normal View History

2026-07-08 19:53:15 +08:00
# 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 并恢复控制