> 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/unity-plugin-beta-overview/features/narrative-design/setting-up-narrative-design-triggers.md).

# 设置叙事设计触发器

## ConvaiNarrativeDesignTrigger 组件

`ConvaiNarrativeDesignTrigger` 会向 Convai 后端发送一个命名信号，使故事图从一个部分推进到下一个部分。它是一个世界空间组件：你可以将其放在任何 GameObject 上——门口、展品、UI 按钮的事件目标——并选择其激活方式。

{% hint style="info" %}
“叙事触发器”与 Unity Physics 触发器并不相同，尽管其中一种激活模式使用 `OnTriggerEnter`。该触发器会向 Convai 后端发送一个命名信号。激活模式控制 *时由* 该信号何时发送。
{% endhint %}

## 添加组件

{% stepper %}
{% step %}
**创建或选择一个 GameObject**

对于基于区域的激活方式（Collision、Proximity、TimeBased），请创建一个空的 GameObject，并将其放置在场景中你希望作为触发区域的位置。对于 Manual 激活，你可以将该组件放在任意位置。
{% endstep %}

{% step %}
**添加组件**

点击 **添加组件** 并导航到 **Convai > Convai Narrative Design Trigger**.

<figure><img src="/files/f31afed5e6e2c20cf7368631c1da21a21b48c430" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}
**指定角色**

将你的 `ConvaiCharacter` 拖入 **Character** 字段。如果留空， **Auto Find Character** 会自动搜索父层级，然后搜索 `ConvaiManager`的角色列表。如果场景中有多个角色，请显式指定目标。
{% endstep %}

{% step %}
**获取并选择一个触发器**

点击 **获取** 在 **Trigger Selection** 部分。SDK 会调用 `NarrativeDesignFetcher.FetchTriggersAsync` 并使用仪表板中为该角色定义的所有触发器填充下拉列表。

选择你希望此组件发送的触发器。 **Trigger Name**, **Trigger ID**，以及 **Destination Section** 字段会自动填充。

<figure><img src="/files/fd46e8f0697313cf3efb9fcd2a656be7b996b08c" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}
**选择一种激活模式**

从四种激活模式中选择一种（如下所述），并配置其设置。
{% endstep %}
{% endstepper %}

## 激活模式

<figure><img src="/files/d99c5bb210f9452811502883c6df79cbaa5e9d96" alt=""><figcaption></figcaption></figure>

### Collision

默认模式。当带有指定标签的玩家 GameObject 进入附加在同一 GameObject 上的碰撞体时，触发器会触发。

**要求：**

* 一个 `Collider` 组件，位于同一 GameObject 上，并且 **Is Trigger** 已启用。
* 触发器 GameObject 或玩家 GameObject 其中之一必须具有 `Rigidbody` ，这样 Unity 物理系统才会生成 `OnTriggerEnter` 回调。

**检测设置：**

| 字段               | 默认值        | 描述                           |
| ---------------- | ---------- | ---------------------------- |
| **Player Tag**   | `"Player"` | 只有带有此标签的 GameObject 会被识别为玩家。 |
| **Player Layer** | 所有层        | 层遮罩，用于进一步筛选哪些对象会被视为玩家。       |

{% hint style="warning" %}
如果 **Is Trigger** 未在碰撞体上启用，或者触发对象和玩家两者都没有 `Rigidbody`, `OnTriggerEnter` ，则永远不会触发。启用 **Validate On Start** 以便在场景运行时自动捕获此问题。
{% endhint %}

### Proximity

当玩家到该组件的距离 `Transform` 落入 **Proximity Radius**范围内时，触发器会触发。该检查会在 `Update`.

中每帧运行。场景视图中会绘制一个绿色球体（选中该 GameObject 时可见）来显示检测半径。你可以直接编辑 **Proximity Radius** 字段来调整其大小。

| 字段                   | 默认值        | 描述                                           |
| -------------------- | ---------- | -------------------------------------------- |
| **Proximity Radius** | `3`        | 以世界单位表示的检测半径。                                |
| **Player Tag**       | `"Player"` | 用于识别玩家的标签。                                   |
| **Auto Find Player** | `true`     | 如果未指定玩家 GameObject，则在场景中搜索带标签的玩家 GameObject。 |

此模式不需要碰撞体。

### TimeBased

当玩家在碰撞体区域内停留达到设定时长后，触发器会触发。如果玩家在延迟结束前离开，倒计时会被取消，并在下次玩家进入时重新开始。

**要求：** 与 Collision 模式相同的碰撞体设置。

| 字段             | 默认值        | 描述                     |
| -------------- | ---------- | ---------------------- |
| **Time Delay** | `0`        | 玩家必须在区域内停留多少秒后触发器才会触发。 |
| **Player Tag** | `"Player"` | 用于识别玩家的标签。             |

### Manual

触发器不会自动执行任何操作。请调用 `InvokeTrigger()` 或 `TryInvokeTrigger()` ，通过你自己的代码或 Unity Event 来触发它。

当激活条件完全由你的游戏逻辑控制时，请使用此模式——例如 UI 按钮、任务完成回调或计分交互。

```csharp
// 通过代码触发该触发器
narrativeTrigger.InvokeTrigger();

// 仅在尚未触发过时才触发（遵循 TriggerOnce）
narrativeTrigger.TryInvokeTrigger();
```

## 自动恢复设置

这些设置使触发器能够更稳健地应对一些常见运行时情况，例如角色或玩家可能无法立即就绪。

<figure><img src="/files/2a8bc86fdb1854eb011504061345e4d00029aa95" alt=""><figcaption></figcaption></figure>

| 字段                      | 默认值    | 描述                                                                     |
| ----------------------- | ------ | ---------------------------------------------------------------------- |
| **Auto Find Character** | `true` | 先搜索父层级，然后搜索 `ConvaiManager.Characters`。如果只存在一个角色，则自动分配；如果找到多个角色，则记录警告。 |
| **Auto Find Player**    | `true` | 先按 Player Tag 搜索，然后按常见名称列表搜索，最后通过 `Camera.main.parent`.                |
| **Queue Until Ready**   | `true` | 如果角色尚未进入活动对话，触发器会被加入队列，并在连接建立后自动触发。                                    |
| **Max Wait Time**       | `30`   | 等待角色就绪的最大秒数。设置为 `0` 表示无超时。                                             |
| **Reset On Scene Load** | `true` | 调用 `ResetTrigger()` ，每当场景被加载时都会执行，以便该触发器在重新加载的场景中可以再次触发。               |

{% hint style="info" %}
“角色就绪”表示 `ConvaiCharacter.IsInConversation` 是 `true` ——实时会话已开启。在会话开启前发送的触发器会保留在队列中，并在连接建立后自动投递。你无需在调用 `IsInConversation` 之前手动检查 `InvokeTrigger()`.
{% endhint %}

{% hint style="warning" %}
将 **Max Wait Time** 为 `0` 设置为在生产构建中会话可能永远无法连接的情况下，会创建一个无限期运行的协程。除非你能够明确控制会话生命周期，否则请始终设置合理的超时时间。
{% endhint %}

## 单次触发与再次触发

**Trigger Once** （默认 `true`）可防止触发器被触发多次。首次成功调用后， `HasTriggered` 会变为 `true`, `CurrentStatus` 会变为 `AlreadyFired`，并且后续所有调用都会返回 `false`.

要允许触发器再次触发，请调用 `ResetTrigger()`:

```csharp
narrativeTrigger.ResetTrigger();
```

`ResetTrigger()` 还会取消任何等待角色就绪的排队触发器。

如果你希望触发器在每次激活时都触发，请在 Inspector 中禁用 **Trigger Once** 。

## 事件参考

| 事件                   | 签名                   | 触发时机                       |
| -------------------- | -------------------- | -------------------------- |
| `OnTriggerActivated` | `UnityEvent`         | 该触发器已成功发送到后端。              |
| `OnPlayerEnterZone`  | `UnityEvent`         | 玩家进入了碰撞体区域或接近区域（在触发器触发之前）。 |
| `OnPlayerExitZone`   | `UnityEvent`         | 玩家离开了碰撞体区域或接近区域。           |
| `OnTriggerFailed`    | `UnityEvent<string>` | 该触发器无法触发。字符串参数包含错误消息。      |
| `OnTriggerQueued`    | `UnityEvent`         | 该触发器已被接受，但由于角色尚未进入对话而被延后。  |

## Trigger Status

该 `CurrentStatus` 属性始终跟踪触发器的状态：

```mermaid
stateDiagram-v2
    [*] --> Ready
    Ready --> AlreadyFired : InvokeTrigger() 成功\n(TriggerOnce = true)
    Ready --> QueuedWaitingForCharacter : 调用了 InvokeTrigger()\n角色未就绪\nQueueUntilReady = true
    Ready --> ConfigurationError : ValidateConfiguration() 失败
    QueuedWaitingForCharacter --> AlreadyFired : 角色变为就绪
    QueuedWaitingForCharacter --> ConfigurationError : 超过 MaxWaitTime
    AlreadyFired --> Ready : ResetTrigger()
    ConfigurationError --> Ready : 修复问题 + ResetTrigger()
    Ready --> Disabled : 组件或 GameObject 被禁用
    Disabled --> Ready : 组件或 GameObject 重新启用
```

有关每种状态的完整解决指南，请参阅故障排除与诊断。

## Inspector 参考

### 角色引用标题

| 字段                      | 默认值    | 描述                                                          |
| ----------------------- | ------ | ----------------------------------------------------------- |
| **Character**           | 无      | 目标 `ConvaiCharacter`。如果留空且 **Auto Find Character** 启用时自动发现。 |
| **Auto Find Character** | `true` | 如果 Character 字段为空，则搜索层级结构和 ConvaiManager。                   |

### 触发器选择标题

| 字段                  | 默认值   | 描述                                              |
| ------------------- | ----- | ----------------------------------------------- |
| **Trigger ID**      | Empty | 选择后为只读。来自仪表板的唯一标识符。                             |
| **Trigger Name**    | Empty | 所选触发器的显示名称。                                     |
| **Trigger Message** | Empty | 随触发器发送的可选消息载荷。可以通过编程方式使用 `SetTriggerMessage()`. |

### 激活设置标题

| 字段                   | 默认值         | 描述                                                         |
| -------------------- | ----------- | ---------------------------------------------------------- |
| **激活模式**             | `Collision` | 触发器如何激活： `Collision`, `Proximity`, `Manual`，或 `TimeBased`. |
| **Proximity Radius** | `3`         | Proximity 模式的检测半径。                                         |
| **Time Delay**       | `0`         | TimeBased 模式的倒计时秒数。                                        |
| **Trigger Once**     | `true`      | 如果启用，则只会触发一次，直到调用 `ResetTrigger()` 。                       |
| **Player Layer**     | 全部          | 用于玩家检测的层遮罩。                                                |
| **Player Tag**       | `"Player"`  | 用于识别玩家 GameObject 的标签。                                     |

### 自动恢复设置标题

| 字段                      | 默认值    | 描述                        |
| ----------------------- | ------ | ------------------------- |
| **Auto Find Player**    | `true` | 如果未检测到玩家，则在场景中搜索带标签的玩家。   |
| **Queue Until Ready**   | `true` | 将触发器延后到角色的会话开启后。          |
| **Max Wait Time**       | `30`   | 队列的超时时间（秒）。 `0` = 无超时。    |
| **Reset On Scene Load** | `true` | 重置 `HasTriggered` 在场景加载时。 |

### 诊断标题

| 字段                    | 默认值     | 描述                                                |
| --------------------- | ------- | ------------------------------------------------- |
| **启用诊断**              | `false` | 将详细的状态转换记录到控制台。                                   |
| **Validate On Start** | `true`  | 运行 `ValidateConfiguration()` 于 Start 时执行，并记录任何问题。 |

## 结论

`ConvaiNarrativeDesignTrigger` 提供四种激活模式——Collision、Proximity、TimeBased 和 Manual——涵盖了从简单穿越区域到 UI 驱动代码流程的各种放置场景。内置的队列系统、可配置的超时时间以及每个触发器的事件，使你无需编写自定义状态管理就能轻松处理边缘情况。继续前往 [模板键：动态叙事变量](/api-docs/zh/cha-jian-yu-ji-cheng/unity-plugin-beta-overview/features/narrative-design/template-keys-dynamic-narrative-variables.md) 以了解如何将诸如玩家姓名或场景参数之类的运行时值注入到角色目标中。


---

# 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:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/unity-plugin-beta-overview/features/narrative-design/setting-up-narrative-design-triggers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
