> 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).

# 角色动作示例

这五个示例从最简单的配置逐步演进到完整的脚本控制。每个示例都是独立的——你无需先阅读其他示例，也可以直接跟着任意一个学习。

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

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

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

#### 检查器配置

在指导员 NPC 的 `GameObject`上添加以下组件：

* `ConvaiCharacter`
* `ConvaiActionConfigSource`
* `ConvaiActionDispatcher` （将这两个策略都保持默认：Queue、StopBatch）
* `NavMeshMoveToActionExecutor` — `_stoppingDistance = 0.6`

在 `ConvaiActionConfigSource`:

**动作定义：**

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

**可操作对象：**

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

**预期结果：**

* "取回灭火器" → NPC 导航到灭火器处，并在距离 0.6 个单位处停下。
* "指向报警面板" → NPC 在 0.5 秒内旋转至面向报警面板。
* "取回报警器" → Convai 会根据描述正确将“alarm”解析为“报警面板”。

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

```
[ConvaiActionDebugProbe] 第 1 步成功：cmd='取回灭火器', def='取回', target=对象:灭火器
```

{% endhint %}

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

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

#### C# 设置

连接 `OnBatchCompleted` 到清单管理器。如果你在 Inspector 中连接它，调度器一侧无需额外代码。若通过代码连接：

```csharp
using 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 定义：**

| 动作名称 | 目标要求 | 执行器                           |
| ---- | ---- | ----------------------------- |
| `走到` | `对象` | `NavMeshMoveToActionExecutor` |
| `演示` | `对象` | `LookAtTargetActionExecutor`  |

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

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

### 示例 3——导航失败与备用对话（错误恢复）

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

#### C# 设置

订阅 `OnStepFailed` 并注入一个动态上下文事件，让 NPC 说出自然的备用回应：

```csharp
using 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)
            ? "该位置"
            : invocation.Command.Target;

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

**预期结果：** NPC 朝危险区域前进， `NavMeshAgent` 却未能完成路径时，执行器返回 `失败`，以及 `OnStepFailed` 触发。系统注入备用事件，NPC 会说出类似“我到不了化学品存放区——路径被脚手架挡住了。”这样的话。

将 `失败策略` 设置为 `StopBatch` （默认）因此当导航步骤失败时，同一批次中的后续步骤（例如“演示危险”）不会运行。

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

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

#### C# 设置

使用 `ConvaiActionDispatcher.EnqueueActions` 用于从时间线触发器或 UI 按钮注入多步序列：

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

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

    // 可从 Unity Timeline 信号、UI 按钮或游戏事件调用此方法
    public void RunDefibrillatorDemo()
    {
        _dispatcher.EnqueueActions(new List<ConvaiActionCommand>
        {
            new ConvaiActionCommand("前往", "设备推车"),
            new ConvaiActionCommand("拿起", "除颤器"),
            new ConvaiActionCommand("前往", "病人床位"),
            new ConvaiActionCommand("指向", "病人床位")
        });
    }
}
```

连接 `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;
using 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("指向", exhibitName)
        {
            WaitForBotSpeech = true,
            DelayAfterBotSpeechSeconds = 0.3f
        };

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

**预期结果：** `pointAction` 是一个新批次的第一步，因此 `ConvaiActionDispatcher` 会在语音门控处将其暂缓，直到运行。门控会在角色的 `OnSpeechStarted`, `OnSpeechStopped`，或 `OnTurnCompleted` 事件触发时释放——以最先发生者为准——然后再等待在 `DelayAfterBotSpeechSeconds` 上设置的额外 0.3 秒，之后再执行指向手势。

只有该批次的第一步会以这种方式受到门控。如果这些事件都不触发，调度器的 `_speechGateTimeoutSeconds` 字段仍会释放该步骤（默认 2 秒，在 Inspector 的 Dispatch 标题下显示为“Speech Gate Timeout Seconds”），因此静默回合也不会让批次卡住。

### 下一步

{% 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
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=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
