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

7.7 KiB
Raw Blame History

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:将所有需要支持 PlayByIdNarrationDataSO 拖入此列表。
  • 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 槽位:

  • RootUI 根节点(用于 Show/Hide
  • Narration TextTMP 文本控件
  • Continue ButtonReach 的 ButtonManager(推荐)
  • Fallback Continue Button:如果你不用 Reach Button,可填 Unity Button
  • Continue Label / Finish Label:按钮文案(继续/确认)

4. 与 TaskSystem 配合(在旁白页事件里加/删任务)

因为 TaskService.AddTask(...) 这类方法需要参数,UnityEvent 直接绑不方便,推荐通过“动作脚本”承接:

  • AddTaskAction
    • 槽位:taskServicetasktimeoutSecondsaddOrUpdateresetStatusToTodo
    • 事件里绑定:AddTaskAction.Invoke()
  • RemoveTaskAction
    • 槽位:taskServicetask
    • 事件里绑定:RemoveTaskAction.Invoke()
  • SetTaskStatusAction
    • 槽位:taskServicetaskstatus
    • 事件里绑定:SetTaskStatusAction.Invoke()

典型用法:

  • 进入第一页(onEnter):添加“寻找钥匙”任务
  • 点击继续离开某页(onContinue):把“寻找钥匙”改为完成/移除

5. 场景搭建步骤(按顺序)

5.1 创建旁白系统根节点

  1. Hierarchy 新建空物体:_NarrationSystem
  2. _NarrationSystem 上 Add ComponentCore.NarrationSystem.NarrationSystem
  3. _NarrationSystem 下新建空物体:Sequences
  4. NarrationSystem.Sequences Root 绑定到 _NarrationSystem/Sequences

5.2 绑定 UI

前提:你已经制作好了旁白 UI(对话框 Text + Button)。

  1. 在旁白 UI 根对象上 Add ComponentUI.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 中设置:
    • idintro_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 ComponentCore.NarrationSystem.NarrationEventListener
  5. 在同物体(或子物体)上 Add ComponentCore.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 ComponentCore.NarrationSystem.NarrationPlayByIdAction
    • Narration System:拖 _NarrationSystem (NarrationSystem)
    • Sequence Id:填 intro_awake
  5. IntroNarrationAction.NarrationPlayByIdAction.Invoke() 绑定到 On Awakening Finished

运行效果:

  • 唤醒动画结束 → 自动弹出旁白 UI → 鼠标可点 → 点击继续翻页 → 最后一页确认后关闭 UI 并恢复控制