# TimelineKit 使用文档 TimelineKit 是 AIBIS Dream 项目中用于统一管理 Unity Timeline 播放的中心化系统。它基于 `PlayableDirector`,提供播放控制、Addressables 动态加载、Yarn 对话集成等功能。 --- ## 目录 1. [系统架构](#系统架构) 2. [快速开始](#快速开始) 3. [配置 DirectorHandler](#配置-directorhandler) 4. [TimelineCenter API](#timelinecenter-api) 5. [Timeline 名称格式](#timeline-名称格式) 6. [Yarn 对话集成](#yarn-对话集成) 7. [代码调用示例](#代码调用示例) 8. [资源组织](#资源组织) 9. [Addressables 配置](#addressables-配置) 10. [常见问题](#常见问题) --- ## 系统架构 ``` ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ TimelineCenter │────▶│ DirectorHandler │────▶│ PlayableDirector│ │ (单例中心) │ │ (场景中的组件) │ │ (Unity 原生) │ └─────────────────┘ └──────────────────┘ └─────────────────┘ │ ├── 注册/注销 Director ├── 播放控制 (播放/暂停/停止/重置) ├── 状态查询 (时间/时长) └── 批量操作 ``` - **TimelineCenter**:单例管理器,负责注册所有 Director 并统一调度 - **DirectorHandler**:挂载在带 `PlayableDirector` 的 GameObject 上,自动向 TimelineCenter 注册 - **TimelineYarnCommand**:提供 Yarn Spinner 命令,可在对话脚本中直接播放 Timeline --- ## 快速开始 ### 1. 场景设置 1. 在场景中创建或选中一个 GameObject 2. 添加 **PlayableDirector** 组件,并分配默认的 Playable Asset 3. **将 PlayableDirector 的 Play On Awake 设为 false**,否则 Timeline 会在场景加载时立刻播放 4. 添加 **DirectorHandler** 组件 5. 在 DirectorHandler 中填写 **Timeline Name**(唯一标识,用于 PlayTimeline 时指定) ### 2. 播放 Timeline ```csharp // 播放该 Director 自带的 Playable Asset TimelineCenter.Instance.PlayTimeline("维修面板"); // 从 Addressables 加载并播放 TimelineCenter.Instance.PlayTimeline("卡扣/卡扣解锁"); ``` --- ## 配置 DirectorHandler | 字段 | 说明 | |------|------| | **timelineName** | Director 的全局唯一名称,供 PlayTimeline 等 API 使用 | | **director** | 关联的 PlayableDirector(通常与组件同一 GameObject,可自动查找) | DirectorHandler 会在 `Start` 时自动向 TimelineCenter 注册,在 `OnDestroy` 时注销。 --- ## TimelineCenter API ### 播放控制 | 方法 | 说明 | |------|------| | `PlayTimeline(string timelineName)` | 播放 Timeline(同步,不等待结束) | | `PlayTimelineAsync(string name)` | 协程版本,播放完成后 yield 返回 | | `StopTimeline(string timelineName)` | 停止播放 | | `PauseTimeline(string timelineName)` | 暂停 | | `ResumeTimeline(string timelineName)` | 恢复播放 | | `ResetTimeline(string timelineName)` | 重置到开头 | | `HideTimeline(string timelineName)` | 隐藏该 Director 的 GameObject(SetActive(false)) | ### 状态查询 | 方法 | 说明 | |------|------| | `GetPlaybackTime(string name)` | 获取当前播放时间(秒) | | `GetDuration(string name)` | 获取 Timeline 总时长(秒) | ### 扩展操作 | 方法 | 说明 | |------|------| | `SetPlaybackSpeed(string name, float speed)` | 设置播放速度 | | `SeekToTime(string name, double time)` | 跳转到指定时间点 | ### 批量操作 | 方法 | 说明 | |------|------| | `PauseAll()` | 暂停所有已注册的 Timeline | | `StopAll()` | 停止所有 | | `ResetAll()` | 重置所有 | --- ## Timeline 名称格式 `timelineName` 支持两种格式: | 格式 | 示例 | 说明 | |------|------|------| | **仅 Director 名** | `"维修面板"` | 播放该 Director 自带的 `playableAsset` | | **Director 名/AddressableKey** | `"卡扣/卡扣解锁"` | 从 Addressables 加载 `Timeline/{AddressableKey}` 并播放 | 解析规则:若包含 `/`,则前半部分为 directorName,后半部分为 addressableKey;否则整个字符串为 directorName。 --- ## Yarn 对话集成 TimelineYarnCommand 提供以下 Yarn 命令,可在 `.yarn` 文件中直接使用: ### play_timeline 播放 Timeline,**会等待播放完成**后再继续对话。 ```yarn // 播放自带 Timeline <> // 播放 Addressable Timeline <> ``` ### reset_timeline 重置 Timeline 到开头。 ```yarn <> ``` ### hide_timeline 隐藏 Timeline 所在的 GameObject。 ```yarn <> ``` ### start_timeline / wait_timeline `start_timeline` 起播但**不等待**;`wait_timeline` 等待**已经在播**的 Timeline 结束(不重头播)。叙事切场景时常用:黑屏下 `start` → 短 wait 稳住首帧 → `fade_out` → `wait_timeline`。完整约定见项目 Skill [`.cursor/skills/narrative-timeline-flow/SKILL.md`](../../../../.cursor/skills/narrative-timeline-flow/SKILL.md)。 ```yarn <> <> <> <> <> ``` --- ## 代码调用示例 ### 直接播放(不等待) ```csharp TimelineCenter.Instance.PlayTimeline("维修面板"); ``` ### 协程中等待播放完成 ```csharp IEnumerator PlayAndDoSomething() { yield return TimelineCenter.Instance.PlayTimelineAsync("卡扣/卡扣解锁"); // 播放完成后执行 Debug.Log("Timeline 播放完毕"); } ``` ### 配合 ActionKit 使用 ```csharp ActionKit.Sequence() .Coroutine(() => TimelineCenter.Instance.PlayTimelineAsync("卡扣/卡扣解锁")) .Callback(() => BlockPuzzleYarnCommand.UnlockSystem()) .Start(this); ``` ### 带完成回调的 DirectorHandler 播放 若直接持有 DirectorHandler 引用,可传入 `onComplete`: ```csharp // 仅适用于 Director 自带的 Asset,非 Addressable directorHandler.Play(() => Debug.Log("播放完成")); ``` --- ## 资源组织 - **Timeline 文件建议放在 `Assets/Animation` 文件夹下**,便于统一管理。 ## Addressables 配置 对于需要动态加载的 Timeline 文件,**Addressable 的 Address 格式为 `Timeline/xxx`**。使用 `DirectorName/AddressableKey` 格式调用时,DirectorHandler 会加载: ``` Timeline/{AddressableKey} ``` 因此需在 Addressables 中: 1. 创建或使用已有 Group(如「石头维修相关资源」) 2. 将 Timeline 资源加入 Group 3. **设置 Address 为 `Timeline/xxx` 格式**(如 `Timeline/卡扣解锁`) 示例(`石头维修相关资源.asset` 中已有): - `Timeline/卡扣解锁` - `Timeline/卡扣锁定` 代码中调用时,`DirectorName/AddressableKey` 的 addressableKey 部分填 `卡扣解锁` 即可,DirectorHandler 会自动补全 `Timeline/` 前缀。 --- ## 常见问题 ### Q: Timeline 一进场景就自动播放? 将 PlayableDirector 组件的 **Play On Awake** 设为 **false**。否则 Unity 会在 Awake 时自动播放,与 TimelineCenter 的播放控制冲突。 ### Q: Timeline 找不到? 确保场景中对应 GameObject 上有 DirectorHandler,且 `timelineName` 与调用时一致。DirectorHandler 在 `Start` 时注册,若场景未完全加载可能尚未注册。 ### Q: Addressable 加载失败? 检查: 1. Addressable 的 Address 是否包含 `Timeline/` 前缀,或与 DirectorHandler 拼出的 key 一致 2. 资源已正确加入 Addressables Group 3. 控制台是否有 `Failed to load PlayableAsset` 等错误 ### Q: 播放完成回调不触发? - `PlayTimeline` / `PlayTimelineAsync` 不直接支持回调,需用协程或 ActionKit 在播放完成后再执行逻辑 - 直接调用 `directorHandler.Play(onComplete)` 时可使用回调,但仅适用于自带 Asset ### Q: 多个 Director 重名? `timelineName` 必须全局唯一,否则后注册的会覆盖先前的。 --- ## 相关文件 - `TimelineCenter.cs` - 中心管理器 - `DirectorHandler.cs` - Director 组件 - `TimelineYarnCommand.cs` - Yarn 命令注册