> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/usage-examples.md).

# 角色动作示例

Convai 角色动作系统的渐进式示例——Inspector 设置、事件订阅、脚本化批量注入以及观察动作。

这六个示例从最简单的配置逐步过渡到完整的脚本控制。每个示例都是独立的——你可以先不看其他示例，直接跟着其中任意一个学习。

### 示例 1 — 消防安全取用（检查器设置，无代码）

**场景：** 消防安全培训模拟。学员提出请求时，讲师 NPC 会取来灭火器。无需编写脚本。

**前置条件：** 场景中已烘焙 NavMesh。

#### 检查器配置

在讲师 NPC 的 `GameObject`上，添加这些组件：

* `ConvaiCharacter`
* `ConvaiActionConfigSource`
* `ConvaiActionDispatcher` （将两项策略都保持默认：Queue，StopBatch）
* `ConvaiWalkToActionExecutor` — `_arriveDistance = 0.6`
* `ConvaiPointAtActionExecutor` ——保持 `保持秒数` 在 `3`。它通过 `ConvaiBodyAnimationController`驱动手臂，因此角色也需要该组件。

在 `ConvaiActionConfigSource`:

**动作定义：**

| 动作名称 | 目标要求 | 执行器                           |
| ---- | ---- | ----------------------------- |
| `取回` | `对象` | `ConvaiWalkToActionExecutor`  |
| `指向` | `任一` | `ConvaiPointAtActionExecutor` |

**可执行对象：**

| 名称     | 说明                           |
| ------ | ---------------------------- |
| `灭火器`  | 安装在主泵控制面板旁墙上支架上的红色便携式二氧化碳灭火器 |
| `警报面板` | 安装在现场入口附近、带红色拉柄的紧急警报面板       |

**预期结果：**

* “取回灭火器” → NPC 前往灭火器并在 0.6 个单位外停下。
* “指向警报面板” → NPC 朝警报面板举起手臂，保持指向 3 秒，然后放下手臂。
* “取回警报” → Convai 会根据描述正确将“alarm”解析为“Alarm Panel”。

{% hint style="success" %}
打开控制台并按以下内容筛选 `ConvaiActionDebugProbe` （如果已添加探针）。你应该会看到：

```
[ConvaiActionDebugProbe] 步骤成功 #1: cmd='Retrieve Extinguisher', def='Retrieve', target=Object:Extinguisher
```

{% endhint %}

### 示例 2 — 入职检查清单集成（事件订阅）

**场景：** 企业入职培训模拟。NPC 演示每个工作站时，检查清单 UI 会推进。完成完整设备参观后，培训阶段会推进。

#### C# 设置

连接 `OnBatchCompleted` 到检查清单管理器。如果你在检查器中完成连接，则分发器一侧无需额外代码。对于通过代码连接：

```csharp
使用 Convai.Runtime.Actions;
using UnityEngine;

public sealed class OnboardingTourController : MonoBehaviour
{
    [SerializeField] private ConvaiActionDispatcher _dispatcher;
    [SerializeField] private TrainingChecklistUI _checklist;

    private void OnEnable()
    {
        _dispatcher.OnBatchCompleted.AddListener(HandleTourStepCompleted);
        _dispatcher.OnBatchAborted.AddListener(HandleTourStepFailed);
    }

    private void OnDisable()
    {
        _dispatcher.OnBatchCompleted.RemoveListener(HandleTourStepCompleted);
        _dispatcher.OnBatchAborted.RemoveListener(HandleTourStepFailed);
    }

    private void HandleTourStepCompleted()
    {
        _checklist.MarkCurrentStepComplete();
        _checklist.AdvanceToNextStep();
    }

    private void HandleTourStepFailed()
    {
        _checklist.MarkCurrentStepIncomplete();
    }
}
```

**ConvaiActionConfigSource 定义：**

| 动作名称 | 目标要求 | 执行器                          |
| ---- | ---- | ---------------------------- |
| `走向` | `对象` | `ConvaiWalkToActionExecutor` |
| `演示` | `对象` | `ConvaiLookAtActionExecutor` |

**可执行对象：** 每个工作站都已按名称和位置描述注册。

**预期结果：** 学员说“给我看看文件系统。”NPC 走到文件柜前，转向它，并 `OnBatchCompleted` 触发——检查清单会自动推进到下一步。

### 示例 3 — 带回退对话的导航失败（错误恢复）

**场景：** 建筑工地安全模拟。当 NPC 无法到达危险区域（路径被阻挡）时，它会承认障碍，而不是静默停止。

#### C# 设置

订阅 `OnStepFailed` 并注入一个动态上下文事件，让 NPC 自然地说出回退台词：

```csharp
使用 Convai.Runtime.Actions;
using UnityEngine;

public sealed class ActionFailureHandler : MonoBehaviour
{
    [SerializeField] private ConvaiActionDispatcher _dispatcher;
    [SerializeField] private ConvaiCharacter _character;

    private void OnEnable() =>
        _dispatcher.OnStepFailed.AddListener(HandleStepFailed);

    private void OnDisable() =>
        _dispatcher.OnStepFailed.RemoveListener(HandleStepFailed);

    private void HandleStepFailed(ConvaiActionInvocation invocation)
    {
        if (invocation.Command.Name != "Move To") return;

        string targetName = string.IsNullOrEmpty(invocation.Command.Target)
            ? "that location"
            : invocation.Command.Target;

        // 告诉 Convai 发生了什么，这样 NPC 就能自然地回应
        _character.DynamicContext.AddEvent(
            $"前往 '{targetName}' 失败——路径被阻挡。");
    }
}
```

**预期结果：** NPC 朝危险区域前进， `NavMeshAgent` 未能完成路径时，执行器返回 `Failed`，以及 `OnStepFailed` 触发。会注入回退事件，NPC 会说出类似“我无法到达化学品存放区——脚手架阻挡了路径。”的话。

设置 `FailurePolicy` 为 `StopBatch` （默认值），这样同一批次中的后续步骤（例如“演示危险”）就不会在导航步骤失败时继续执行。

### 示例 4 — 脚本化演示序列（程序化注入）

**场景：** 医疗程序培训模拟。在培训脚本中的预定时刻（由时间轴事件触发），NPC 会自动完成一段设备演示，而无需等待学员发问。

#### C# 设置

使用 `ConvaiActionDispatcher.EnqueueActions` 从时间轴触发器或 UI 按钮注入一个多步骤序列：

```csharp
using System.Collections.Generic;
使用 Convai.Runtime.Actions;
using Convai.Shared.Types;
using UnityEngine;

public sealed class DemonstrationTrigger : MonoBehaviour
{
    [SerializeField] private ConvaiActionDispatcher _dispatcher;

    // 当 NPC 本轮的口头回答已被派发后调用此方法
    public void RunDefibrillatorDemo()
    {
        _dispatcher.EnqueueActions(new List<ConvaiActionCommand>
        {
            new ConvaiActionCommand("Move To", "Equipment Cart"),
            new ConvaiActionCommand("Pick Up", "Defibrillator"),
            new ConvaiActionCommand("Move To", "Patient Bed"),
            new ConvaiActionCommand("Point At", "Patient Bed")
        });
    }
}
```

连接 `RunDefibrillatorDemo` 到 `UnityEngine.Timeline` 信号、UI 按钮 `OnClick`，或场景中的任何其他触发器。

**预期结果：** 讲师 NPC 走到设备推车旁，拿起除颤器，走到病床旁，并指向它——整个过程无需学员说任何话。 `OnBatchCompleted` 在序列结束时触发，你可以用它来推进培训阶段。

{% hint style="info" %}
`BatchPolicy = Queue` 可确保此脚本序列在学员与当前活动动作批次正在对话时会耐心等待。若要中断当前进行中的任何动作，请改为 `BatchPolicy = ReplaceCurrent` 。
{% endhint %}

### 示例 5 — 与语音同步的展品指引（语音门控）

**场景：** 博物馆导览模拟。当游客询问某件展品时，NPC 会先口头回答，然后再指向它。指向动作必须等到角色的语音台词真正开始播放后才能启动，否则 NPC 看起来会在说话前就先指向展品。

#### C# 设置

设置 `WaitForBotSpeech` 和 `DelayAfterBotSpeechSeconds` 在命令上，在入队前：

```csharp
using System.Collections.Generic;
使用 Convai.Runtime.Actions;
using Convai.Shared.Types;
using UnityEngine;

public sealed class ExhibitPointerTrigger : MonoBehaviour
{
    [SerializeField] private ConvaiActionDispatcher _dispatcher;

    // 在本轮中 NPC 的口头回答已派发后调用此方法
    public void PointAtExhibit(string exhibitName)
    {
        var pointAction = new ConvaiActionCommand("Point At", exhibitName)
        {
            WaitForBotSpeech = true,
            DelayAfterBotSpeechSeconds = 0.3f
        };

        _dispatcher.EnqueueActions(new List<ConvaiActionCommand> { pointAction });
    }
}
```

**预期结果：** `pointAction` 是一个新批次的第一步，因此 `ConvaiActionDispatcher` 会在运行前将其置于语音门控处。一旦角色的 `OnSpeechStarted`, `OnSpeechStopped`，或 `OnTurnCompleted` 事件触发——无论哪个先发生——然后再等待上设置的额外 0.3 秒 `DelayAfterBotSpeechSeconds` ，然后再执行指向手势。

只有批次中的第一步会以这种方式被门控。如果这些事件都没有触发，分发器的 `_speechGateTimeoutSeconds` 字段仍会放行该步骤（默认 2 秒，在检查器中 Dispatch 标题下显示为“Speech Gate Timeout Seconds”），因此沉默的轮次不会让批次停滞。

### 示例 6 — 博物馆展品的距离检查（观察动作）

**场景：** 博物馆导览模拟。游客询问某件展品有多远，NPC 则回答一个距离，而不是执行动作。这种动作的形态与前五个示例不同：执行器的职责是组织答案，而不是移动或做手势。

#### 检查器配置

在讲师 NPC 的 `GameObject`，请在 `ConvaiMeasureDistanceActionExecutor` (`添加组件 > Convai > 动作 > 测量距离`）。它不需要同级组件——如果未解析到目标，它就改为测量到玩家的距离。

在 `ConvaiActionConfigSource`:

**动作定义：**

| 动作名称   | 目标要求 | 执行器                                   |
| ------ | ---- | ------------------------------------- |
| `测量距离` | `任一` | `ConvaiMeasureDistanceActionExecutor` |

将执行器的 **距离区间** 字段保持默认值（`触手可及` `1.2`, `几步之遥` `3.5`, `跨越整个区域` `9`），并将 **包含米数** 保持勾选，这样口头回答会包含测量值。

在动作定义中，将 **回答传递** 为 `告诉玩家` ——这是 SDK 推荐用于任何回答问题的动作的设置，例如读取仪表、计数或测量距离。

**预期结果：**

* “恐龙骨架有多远？” → 执行器解析目标，测量地面平面距离，并返回一个已回答的结果，例如 `“恐龙骨架就在几步之外。大约 2.8 米。”` ——Convai 会把答案说给游客听。
* “我离得有多远？” → 在未解析到目标时，执行器会改为测量到玩家的距离，并回答 `你就在触手可及的范围内。大约 0.9 米。`

`ConvaiMeasureDistanceActionExecutor` 返回 `ConvaiActionExecutionResult.Answered(...)` 而不是 `Succeeded(...)`。已回答的结果会携带 Convai 被允许说出的句子；除此之外，结果中的其他内容都不会进入角色对世界的模型。 `ConvaiCountTargetGroupActionExecutor` (`Convai/Actions/计数目标组`）遵循相同的模式，用于统计一个 `ConvaiActionTargetGroup`.

### 下一步

{% content-ref url="/pages/1398e3302b345ef93934a0e6c93b4d8e576ab00e" %}
[排查角色动作问题](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/debugging-and-troubleshooting.md)
{% endcontent-ref %}

{% content-ref url="/pages/0341126fa4c492311dab4fb6aca6d0c64191016b" %}
[角色动作脚本参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/actions-scripting-reference.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/character-actions/usage-examples.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
