分发器与批处理策略
通过其 UnityEvent API 控制分发器如何编排操作批次、解决命令冲突,并公开生命周期事件。
ConvaiActionDispatcher 组件
ConvaiActionDispatcher 是动作系统的运行时引擎。它挂在你的 NPC 的 GameObject 上,监听来自 Convai 后端的动作命令,并按照你配置的策略,依次为每个命令运行正确的执行器。
通过选择你的 NPC 的 GameObject 并单击 添加组件 → Convai Action Dispatcher.
ConvaiActionDispatcher 需要一个 ConvaiCharacter 组件,且位于同一个 GameObject 上。它会订阅 ConvaiCharacter.OnActionsReceived 并在启用时自动订阅。

理解批次
Convai 后端可能返回 在单个响应中返回多个动作。这组动作称为一个 批次.
例如,如果玩家说:
“把安全头盔捡起来并拿给我。”
后端可能返回一个包含两个动作的批次:
Move To→ 目标:安全头盔拾取→ 目标:安全头盔
调度器会在批次内运行动作 按顺序 ——一次一个,按顺序执行。它会等每个执行器完成后再开始下一步。
批次策略
该 批次策略 决定当调度器仍在执行上一批动作时,新批次动作到达会发生什么。
在以下位置配置它: 调度 部分中的 ConvaiActionDispatcher 检视面板。
Queue (默认)
新批次会在队列中等待。各批次按接收顺序执行。
回合制体验、训练模拟、顺序叙事
替换当前
正在运行的批次会立即取消。新批次会立刻开始。
适合实时游戏,玩家应能在动作执行中途重新引导 NPC
丢弃传入
新批次会被丢弃。当前批次会不受干扰地完成。
过场动画、脚本化序列、不可中断行为
Queue 对大多数应用来说,这是最安全的默认选项。NPC 会在开始下一个任务之前完成当前任务,从而产生可预测的行为。
替换当前 让 NPC 在实时场景中感觉更灵敏、更有响应。适用于玩家指令应始终立即生效的情况。

失败策略
该 失败策略 决定当批次中的某个动作失败时会发生什么——例如,执行器找不到目标,或者 NavMesh 路径无效。
停止批次 (默认)
批次中的剩余动作将被跳过。 OnBatchAborted 会触发。
继续批次
无论失败与否,调度器都会继续执行下一个动作。 OnBatchCompleted 在所有步骤完成时触发。
停止批次示例 ——批次: [移动到木箱, 拾取木箱]
如果 移动到木箱 失败(例如,找不到 NavMesh 路径), 拾取木箱 会被跳过,并且 OnBatchAborted 触发。角色不会尝试拾取一个它从未到达的物体。
继续批次示例 ——批次: [挥手, 移动到木箱, 点头]
如果 移动到木箱 失败,调度器仍会执行 点头。适用于动作彼此独立的情况。

UnityEvents
ConvaiActionDispatcher 在其 Inspector 的 事件 部分中提供了一整套 UnityEvents。将它们连接到场景中的任意方法,即可响应动作生命周期事件。
批次事件
批次开始时
新批次开始执行
()
批次完成时
批次中的所有步骤都已完成(包括返回 未处理)
()
批次中止时
由于失败而提前停止了一个批次(停止批次策略)
()
步骤事件
步骤开始时
单个动作步骤开始
(ConvaiActionInvocation)
步骤成功时
执行器返回了 成功
(ConvaiActionInvocation)
步骤失败时
执行器返回了 失败, 超时,或 Canceled;或者定义/目标缺失
(ConvaiActionInvocation)
步骤未处理时
执行器返回了 未处理
(ConvaiActionInvocation)
步骤事件会接收一个 ConvaiActionInvocation 参数。这使你可以访问动作命令、定义、已解析的目标,以及它在批次中的第几步。可用它来构建具备上下文感知的 UI、日志或游戏玩法响应。

示例:连接事件
在批次运行时显示加载指示器:
批次开始时→LoadingSpinner.SetActive(true)批次完成时→LoadingSpinner.SetActive(false)批次中止时→LoadingSpinner.SetActive(false)
当动作成功时更新任务追踪器:
步骤成功时→QuestTracker.OnActionCompleted(ConvaiActionInvocation)
将失败记录到训练评分系统:
步骤失败时→ScoreManager.OnActionFailed(ConvaiActionInvocation)
脚本 API
如果你需要从自己的代码中触发动作,而不是等待后端响应,你可以调用 EnqueueActions 直接:
EnqueueActions 遵循相同的 批次策略 与后端接收的命令相同的处理方式。如果策略是 Queue,注入的批次会等待轮到它执行。
高级:不通过调度器接收动作
ConvaiActionDispatcher 处理完整的动作管线,是大多数项目的正确选择。如果你需要完全自定义的管线,可以直接订阅 ConvaiCharacter.OnActionsReceived 代替。
每个 ConvaiActionCommand 包含两个字段:
名称
string
后端选择的动作名称(例如, "Move To")
目标
string
原始目标名称字符串。若没有目标,则为 Null 或空。
HasTarget
bool
true 如果 目标 非空且不为空字符串
直接订阅意味着你会失去调度器的所有功能——批次策略、失败策略、自动目标解析以及 UnityEvent 接口。你需要自行处理所有内容。
正确订阅
请始终在 OnDisable中取消订阅。否则会导致过期的处理程序在组件销毁后仍被触发。
房间级订阅
如果你的监听器位于会话或管理器级别——例如,一个同时观察多个角色动作的训练评估管理器——请改为订阅 ConvaiManager 上的全房间事件:
ConvaiManager.Events.OnCharacterActionReceived 会针对 房间中的所有角色触发 并包含 characterId。当你的组件已经附加在 NPC 的 GameObject 上时,请使用角色级 OnActionsReceived 订阅。当你的逻辑是集中式的,并且需要观察多个角色时,请使用房间级事件。
两者一起使用
ConvaiActionDispatcher 和自定义订阅者可以在同一个角色上共存——二者都会接收到相同的批次。这对于在正常执行的同时进行分析或日志记录很有用:
结论
ConvaiActionDispatcher 让你可以精确控制动作批次的排序方式、冲突时的处理,以及失败如何处理。UnityEvent 接口让你无需编写调度器子类,就能对执行的每个阶段做出响应——从批次开始到单个步骤结果都包括在内。对于测试或脚本化序列, EnqueueActions 可让你直接从代码中注入批次。对于完全自定义的管线, OnActionsReceived 则提供对每个传入命令的原始访问。
下一步:编写自定义执行器——构建内置执行器未涵盖的任何行为。
最后更新于
这有帮助吗?