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

编写自定义动作执行器

在 MonoBehaviour 上实现 IConvaiActionExecutor,以将自定义移动、库存、UI 或物理行为连接到 Convai 动作管线。

当内置执行器不符合你项目的移动系统、交互模式或游戏规则时,请实现 IConvaiActionExecutor。自定义执行器是一个标准的 C# MonoBehaviour ,带有一个异步方法。调度器会将其与任何内置执行器一视同仁——所有策略、事件和取消行为都会自动应用。

何时构建自定义执行器

在以下情况下构建自定义执行器:

  • 你的项目使用自定义移动系统(根运动、 CharacterController、转向行为)

  • 某个动作会修改库存、UI 状态、任务标记或物理对象

  • 某个动作会调用外部服务或触发基于协程的动画系统

  • 你需要条件逻辑——例如,一个会根据角色状态表现不同的动作

IConvaiActionExecutor 接口

public interface IConvaiActionExecutor
{
    Task<ConvaiActionExecutionResult> ExecuteAsync(
        ConvaiActionInvocation invocation,
        CancellationToken cancellationToken);
}

在任何 MonoBehaviour上实现此接口。调度器会调用 ExecuteAsync 对每个步骤执行并等待结果,然后再继续下一个步骤。请让任务保持存活,直到游戏逻辑工作完成——如果过早返回,即使动画或移动仍在进行,也会结束该步骤。

执行器运行在 Unity 主线程上。你可以安全地调用 Unity API(transform, GetComponent, Instantiate等)在 ExecuteAsync中的任何地方。使用 await Task.Yield() 可以让出一帧而不离开主线程。

ConvaiActionInvocation 对象

每个 ExecuteAsync 调用会接收一个 ConvaiActionInvocation ,其中包含执行该行为所需的一切:

属性
类型
包含

命令

ConvaiActionCommand

原始后端命令—— 名称, 目标, 有目标

定义

ConvaiActionDefinition

本地定义—— ActionName, TargetRequirement, Executor, TimeoutSeconds

已解析目标

ConvaiResolvedActionTarget

已解析的目标绑定—— 类型, 名称, 对象绑定, 角色绑定, GameObjectReference

角色

ConvaiCharacter

正在执行的 NPC

批次索引

int

在调度器生命周期内此批次的顺序索引

步骤索引

int

当前批次中此步骤的索引(从 0 开始)

访问目标 GameObject ,带有:

不要重新解析 invocation.Command.Nameinvocation.Command.Target 来重新推导该做什么。使用 invocation.Definitioninvocation.ResolvedTarget ——它们已经完成解析并验证。

执行结果类型

请从以下工厂方法之一返回 ExecuteAsync:

工厂方法
何时使用

ConvaiActionExecutionResult.Succeeded()

行为已成功完成

ConvaiActionExecutionResult.Failed(string message = null, Exception exception = null)

发生了真实错误(缺少组件、状态无效、游戏流程失败)

ConvaiActionExecutionResult.Unhandled(string message = null)

此执行器有意拒绝处理该调用(上下文不正确或目标类型不对)

ConvaiActionExecutionResult.Canceled()

CancellationToken 已发出信号——当你在循环中观察到取消时返回此值

失败未处理: 使用 失败 当你尝试执行该行为但出现问题时使用。使用 未处理 当此执行器根本不应处理此特定调用时使用——例如目标类型不正确。调度器会触发 OnStepFailed 关于 失败OnStepUnhandled 关于 未处理;两者都被视为对 StopBatch 失败策略。

取消

CancellationToken 会在以下情况下触发:

  1. BatchPolicy.ReplaceCurrent 生效(新的批次会抢占当前批次)

  2. TimeoutSeconds 在动作定义上过期

  3. 调度器被禁用或销毁

请始终在任何循环中或每次 await:

如果你的代码捕获到 OperationCanceledException,则返回 ConvaiActionExecutionResult.Canceled() 立即:

或者,让 ThrowIfCancellationRequested 向上冒泡。调度器会将你的 ExecuteAsync 包裹在 try/catch 中,并将未捕获的 OperationCanceledException已取消

完整示例:高亮对象执行器

此执行器会在已解析目标上启用轮廓效果,等待三秒,然后将其禁用。

复合动作

将整个游戏流程放入一个 ExecuteAsync。调度器会将一个动作定义视为不可分割——它会等待你的任务完成后才开始下一步。对于拾取、检查、先打开再拿取,或任何包含多个子行为的序列,这都是正确的模式。

执行器设计规则

  • 使用 invocation.ResolvedTarget,而不是 invocation.Command.Target. 调度器已经将名称解析为一个 GameObject 绑定——不要重新解析原始字符串。

  • 返回 未处理 当此执行器不合适时。 单个执行器组件可以在多个动作定义之间共享。返回 未处理 会向调度器发出信号以触发 OnStepUnhandled ,而不会将其视为严重失败。

  • 设置 TimeoutSeconds 在动作定义中。 请使用超时机制,而不是在执行器内部实现你自己的截止时间逻辑。

  • 在取消时清理。 如果你的执行器启用了某个效果、移动了一个对象,或持有了某个资源,请在返回前释放它 已取消.

  • 不要在多次调用之间保留状态。 同一个执行器实例可能会在多个批次中针对不同目标被调用。不要假设上一次调用的状态仍然有效。

下一步

配置角色动作角色动作脚本参考

最后更新于

这有帮助吗?