# 帧动画角色配置指南(策划版) 本文说明帧动画角色的 **Flow 配置**与 **Yarn 调用**。Clip 的切图、导入和帧时长配置不在本文展开。 示例资源:`Assets/GameContent/Huoshan/Actor/火山Graph.asset` > 当前的 `火山Graph` 已有 Clip,但还没有配置 Flow。下文的 Flow 名称是教学示例,不代表资源中已经存在。 ## 1. 先理解 Clip 和 Flow - **Clip**:一段独立帧动画,例如 `摘帽`、`扣头切屏特效`、`伸手表情idle`。 - **Flow**:把多个 Clip 按顺序串成一次完整表演,例如 `摘帽 → 伸手表情idle`。 - Yarn 调用时,Clip ID 和 Flow ID 的写法完全相同,系统会自动查找对应内容。 适合直接调用 Clip 的情况:只播放一个动作或切换一个循环表情。 适合配置 Flow 的情况:动作需要连续播放多个阶段,并且希望 Yarn 只写一条命令。 ## 2. 打开火山 Graph 1. 在 Project 窗口选中 `Assets/GameContent/Huoshan/Actor/火山Graph.asset`。 2. 点击 Inspector 中的 **Open Frame Animation Graph Editor**。 3. 也可以从 Unity 菜单打开:**Window > Aibis Dream > Frame Animation Graph Editor**,再选择 `火山Graph`。 编辑器左侧是 Clip / Flow 列表,中间是节点画布,右侧是当前选中内容的属性。 ## 3. 配置一个 Flow 下面以新建 `摘帽到伸手_Flow` 为例,预期顺序为: ```text 摘帽 → 伸手表情idle(循环) ``` ### 第一步:把 Clip 放到画布 1. 在左侧选择 **Clips**。 2. 把 `摘帽` 从左侧拖到中间画布,生成一个 Node。 3. 再把 `伸手表情idle` 拖到画布,生成第二个 Node。 同一个 Clip 可以在画布中生成多个 Node。Node 只是 Flow 中对 Clip 的一次引用,不会复制或修改原 Clip。 ### 第二步:连接播放顺序 从 `摘帽` Node 右侧的输出点拖线,连接到 `伸手表情idle` Node 左侧的输入点。 当前 Flow 只支持单线顺序播放: - 一个 Node 最多只能连接一个后继 Node; - 不支持分支; - 不支持把路径连成环; - 播放顺序由连线决定,不由节点在画布上的左右位置决定。 ### 第三步:创建 Flow 并指定入口 1. 选中 `摘帽` Node。 2. 右键该 Node,选择 **Create Flow From Node**;也可用画布上方 **Canvas > Create Flow From Selection**。 3. 将 Flow ID 填为 `摘帽到伸手_Flow`。 4. 确认入口是 `摘帽` Node。入口 Node 会显示 **E** 标记。 Flow ID 就是 Yarn 中填写的动画名。建议使用有明确含义且不易重复的名称,例如 `摘帽到伸手_Flow`。 > Clip ID 和 Flow ID 共用同一套命名空间,不能重名。修改 ID 后,已有 Yarn 文本不会自动更新,必须同步搜索并修改调用。 ### 第四步:设置结尾行为 选中最后一个 Node,在右侧设置 **Override End Behavior**。常用选项: | 选项 | 播放结束后的表现 | 常见用途 | | --- | --- | --- | | `Loop` | 从头循环最后一个 Clip | idle、持续表情 | | `HoldLastFrame` | 停在最后一帧 | 一次动作的定格结尾 | | `Clear` | 清空当前 Sprite | 动画结束后不显示图片 | | `HideTarget` | 隐藏渲染目标 | 动画结束后隐藏角色 | 本例最后的 `伸手表情idle` 应使用 `Loop`。 注意:只有终点 Node 才能设置结束行为。一个 Node 如果设置了结束行为,就不能再连接后继 Node。中间 Node 播完后会自动进入下一个 Node,不需要设置结束行为。 如需单独调整某个 Node 的速度,可勾选 **Override Speed**:`1` 为原速,`2` 为两倍速,`0.5` 为半速。速度必须大于 `0`。 ### 第五步:预览、校验和保存 1. 在左侧选择刚创建的 Flow,点击右侧 **Focus Flow On Canvas**。 2. 使用预览区的播放按钮检查顺序和循环结果。 3. 点击顶部 **Validate**,底部 **Validation** 中不能有 Error。 4. 点击顶部 **Save** 保存。 ## 4. Yarn 调用 ### 初始化角色 帧动画角色首次出现时,先初始化: ```yarn <> ``` 参数依次为: ```text 角色名 槽位名 角色类型 ``` `火山` 会加载 Addressable 地址为 `FrameAnimation/火山` 的 Graph。`init_actor` 会等待角色 Prefab 和 Graph 加载完成,因此下一行可以直接切动画。 同一段角色出场流程中只需初始化一次,不要在每次换动画前重复初始化。 > 初始化完成后不会自动播放 Graph 中的 Default Playable,需要再调用一次 Clip 或 Flow。 ### 调用一个 Clip 把 **Clip ID** 直接写在命令的第一个参数中: ```yarn <> ``` 这条命令会直接播放 `火山Graph` 中的 `捂头表情idle` Clip。Clip 播完后的表现由该 Clip 的 **End Behavior** 决定: - `Loop`:持续循环,直到被下一次状态切换替换; - `HoldLastFrame`:播放一次并停在最后一帧; - `Clear`:播放一次后清空图片; - `HideTarget`:播放一次后隐藏角色渲染目标。 #### Clip:播放后立刻继续 Yarn ```yarn <> hs: 我太伤心了。 ``` `change_actor_state` 只负责开始播放,Yarn 不会等 Clip 播完,会立即执行下一行。适用于: - 切换 idle 或持续循环表情; - Clip 需要和对白同时播放; - 后续时机由策划自己用 `wait` 控制。 #### Clip:播放完成后再继续 Yarn ```yarn <> <> ``` `change_actor_state_async` 会等待 Clip: - 非循环 Clip:等待整段播放结束; - `Loop` Clip:等待第一轮播放结束,然后继续执行 Yarn;动画本身仍会循环。 因此,一次性动作之后要准确切换 idle 时,推荐使用上面的“异步动作 Clip → 循环 idle Clip”写法,不需要猜测 `wait` 秒数。 ### 调用一个 Flow Flow 的调用格式与 Clip 完全相同,只需把第一个参数换成 **Flow ID**。例如已配置 `摘帽到伸手_Flow`: #### Flow:播放后立刻继续 Yarn ```yarn <> hs: 戴上“实实”牌帽子,给你的头顶添件宝! ``` Yarn 会立即继续对白,Flow 则在后台按照连线依次播放。适合整段表演与对白同时发生的情况。 #### Flow:播放到终点首轮后再继续 Yarn ```yarn <> // Flow 的前置动作和终点 Loop 首轮播放完后,才执行这里 ``` `change_actor_state_async` 会从入口开始等待整条 Flow: - 终点为非循环 Clip:等待所有节点自然播放结束; - `前置动作 → 终点 Loop` 的 Flow:等待前置动作和终点 Loop 的第一轮全部结束。 如果终点是 `Loop`,命令返回后终点 Clip 仍会继续循环,直到被下一次状态切换替换。 ### 快速选择命令 | 要播放的内容 | 希望 Yarn 是否等待 | 写法 | | --- | --- | --- | | 单个 Clip | 不等待 | `<>` | | 单个 Clip | 等完整动画;Loop 等第一轮 | `<>` | | 一整条 Flow | 不等待 | `<>` | | 一整条 Flow | 等到终点首轮完成 | `<>` | 命令本身不需要标明目标是 Clip 还是 Flow。系统会用 ID 在当前角色的 Graph 中查找;因此 Clip ID 和 Flow ID 不能重名。 ### 名称中有空格时 Clip ID、Flow ID、角色名或槽位名中包含空格时,必须加英文双引号: ```yarn <> <> ``` 不含空格时可以不加;为减少出错,也可以统一加英文双引号。 ## 5. 火山的完整示例 下面同时演示 Clip 和 Flow 调用,并假设已按前文创建 `摘帽到伸手_Flow`: ```yarn <> // 调用 Loop Clip:立即继续 Yarn,idle 在对白期间持续循环 <> <> hs: 医——生——救——我——! // 调用 Flow:等“摘帽”播完,再等终点“伸手表情idle”完成第一轮 <> // Flow 返回后,终点的伸手 idle 仍在循环 hs: 戴上“实实”牌帽子,给你的头顶添件宝! // 调用一次性 Clip,并等待它完整播完 <> // 再调用另一个 Loop Clip,替换当前状态并继续对白 <> hs: 我……没有活干了。 ``` ## 6. 提交前检查 - Flow 的入口是否是第一个动作,而不是终点 idle? - 节点是否按预期连线,且没有分支或环? - 只有最后一个 Node 设置了结束行为吗? - 需要持续显示的 idle 是否设置为 `Loop`? - Flow ID 是否与已有 Clip / Flow 重名? - Yarn 中的 ID 与 Graph 完全一致,包括空格和大小写吗? - 需要等动画时是否用了 `change_actor_state_async`? - 顶部 **Validate** 是否无 Error? - 是否点击 **Save**? ## 7. 常见问题 **调用后没有动画** 先检查角色是否用 `FrameAnimation` 类型初始化,再检查 Graph 的 Addressable 地址是否为 `FrameAnimation/角色名`。火山应为 `FrameAnimation/火山`。 **提示 playable 找不到** Yarn 中传入的是 Clip ID 或 Flow ID,不是资源文件名、Graph 名或 Node 的 Display Name。检查字符、空格和大小写是否完全一致。 **动画刚开始就被打断** 后面很可能紧跟了另一条 `change_actor_state`。普通命令不会等待;需要等当前动画完成时改用 `change_actor_state_async`。 **循环动画导致剧情无法继续** 使用 `change_actor_state_async` 等待 Loop 时,只会等待第一轮,不会无限阻塞。如果仍未继续,先运行 **Validate** 检查 Flow 路径和结尾配置。 **想让 Flow 中途停住** 当前 Flow 是顺序播放,不支持分支或中途等待 Yarn。应拆成两个 Clip / Flow,在 Yarn 中分两次调用。