For the complete documentation index, see llms.txt. This page is also available as Markdown.

分发器与批处理策略

通过其 UnityEvent API 控制分发器如何编排操作批次、解决命令冲突,并公开生命周期事件。

ConvaiActionDispatcher 组件

ConvaiActionDispatcher 是动作系统的运行时引擎。它挂在你的 NPC 的 GameObject 上,监听来自 Convai 后端的动作命令,并按照你配置的策略,依次为每个命令运行正确的执行器。

通过选择你的 NPC 的 GameObject 并单击 添加组件 → Convai Action Dispatcher.

ConvaiActionDispatcher 需要一个 ConvaiCharacter 组件,且位于同一个 GameObject 上。它会订阅 ConvaiCharacter.OnActionsReceived 并在启用时自动订阅。


理解批次

Convai 后端可能返回 在单个响应中返回多个动作。这组动作称为一个 批次.

例如,如果玩家说:

“把安全头盔捡起来并拿给我。”

后端可能返回一个包含两个动作的批次:

  1. Move To → 目标: 安全头盔

  2. 拾取 → 目标: 安全头盔

调度器会在批次内运行动作 按顺序 ——一次一个,按顺序执行。它会等每个执行器完成后再开始下一步。


批次策略

批次策略 决定当调度器仍在执行上一批动作时,新批次动作到达会发生什么。

在以下位置配置它: 调度 部分中的 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 如果 目标 非空且不为空字符串

正确订阅

请始终在 OnDisable中取消订阅。否则会导致过期的处理程序在组件销毁后仍被触发。

房间级订阅

如果你的监听器位于会话或管理器级别——例如,一个同时观察多个角色动作的训练评估管理器——请改为订阅 ConvaiManager 上的全房间事件:

ConvaiManager.Events.OnCharacterActionReceived 会针对 房间中的所有角色触发 并包含 characterId。当你的组件已经附加在 NPC 的 GameObject 上时,请使用角色级 OnActionsReceived 订阅。当你的逻辑是集中式的,并且需要观察多个角色时,请使用房间级事件。

两者一起使用

ConvaiActionDispatcher 和自定义订阅者可以在同一个角色上共存——二者都会接收到相同的批次。这对于在正常执行的同时进行分析或日志记录很有用:


结论

ConvaiActionDispatcher 让你可以精确控制动作批次的排序方式、冲突时的处理,以及失败如何处理。UnityEvent 接口让你无需编写调度器子类,就能对执行的每个阶段做出响应——从批次开始到单个步骤结果都包括在内。对于测试或脚本化序列, EnqueueActions 可让你直接从代码中注入批次。对于完全自定义的管线, OnActionsReceived 则提供对每个传入命令的原始访问。

下一步:编写自定义执行器——构建内置执行器未涵盖的任何行为。

最后更新于

这有帮助吗?