> 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/scripting-reference/character-and-player-api.md).

# 角色和玩家 API

角色与玩家脚本组件参考，涵盖会话控制、语音、音频和注意力目标定位。

`ConvaiCharacter` 控制单个 AI 角色的会话、语音、远程音频、动态上下文和注意力目标。 `ConvaiPlayer` 表示本地人类参与者，并提供文本消息发送和身份配置。两个组件都由以下对象拥有并跟踪： `ConvaiManager`.

***

### 访问组件

```csharp
// 通过 Inspector 字段（推荐）
[SerializeField] private ConvaiCharacter _character;

// 通过管理器拥有列表
var character = ConvaiManager.ActiveManager?.Characters[0];

// 通过管理器的活动对话目标
var active = ConvaiManager.ActiveManager?.ActiveConversationCharacter;

// 玩家
var player = ConvaiManager.ActiveManager?.Player;
```

***

### `ConvaiCharacter`

#### 属性

| 属性                                | 类型                       | 访问  | 说明                                    |
| --------------------------------- | ------------------------ | --- | ------------------------------------- |
| `角色 ID`                           | `字符串`                    | 读取  | Convai 角色标识符                          |
| `CharacterName`                   | `字符串`                    | 读取  | 角色的显示名称                               |
| `OwnerId`                         | `字符串`                    | 读取  | 所有者账户标识符                              |
| `SessionState`                    | `SessionState`           | 读取  | 此单个角色的当前会话状态                          |
| `IsCharacterReady`                | `布尔值`                    | 读取  | 当角色已完成就绪握手时为 True                     |
| `IsSessionConnected`              | `布尔值`                    | 读取  | 当此角色的会话处于 `已连接` 状态时为 True             |
| `IsInConversation`                | `布尔值`                    | 读取  | 当此角色是当前活动对话目标时为 True                  |
| `IsSpeaking`                      | `布尔值`                    | 读取  | 当角色正在主动产生音频输出时为 True                  |
| `IsRemoteAudioEnabled`            | `布尔值`                    | 读取  | 当此角色的远程音频输出已启用时为 True                 |
| `CurrentEmotion`                  | `字符串`                    | 读取  | 从 Convai 接收到的最近情绪标签                   |
| `CurrentEmotionIntensity`         | `整数`                     | 读取  | 最近的情绪强度（1–3）                          |
| `ConfigurationSource`             | `ConvaiConfigSourceMode` | 读取  | 配置来自 Inspector 字段还是配置文件资源             |
| `CharacterConfigAsset`            | `ConvaiCharacterProfile` | 读取  | 当 `ConfigurationSource` 为基于资源时的配置文件资源 |
| `NameTagColor`                    | `颜色`                     | 读取  | 用于 UI 中此角色姓名标签的颜色                     |
| `EnableRemoteAudioOnStart`        | `布尔值`                    | 读取  | 远程音频输出是否在启动时默认启用                      |
| `EnableSessionResume`             | `布尔值`                    | 读取  | 会话在重新连接后是否尝试恢复                        |
| `CharacterReadyTimeoutSeconds`    | `float`                  | 读/写 | 等待角色就绪握手的超时时间（秒）                      |
| `InitialDynamicInfoText`          | `字符串`                    | 读取  | 会话开始时发送的动态上下文文本                       |
| `InitialDynamicInfoKeepInContext` | `布尔值`                    | 读取  | 初始动态上下文是否在多轮对话中持续保留                   |
| `ActionConfig`                    | `ConvaiActionConfig`     | 读取  | 此角色的动作配置                              |
| `DynamicContext`                  | `IConvaiDynamicContext`  | 读取  | 动态上下文命令接口                             |
| `NarrativeDesign`                 | `IConvaiNarrativeDesign` | 读取  | 叙事设计接口                                |
| `IsInjected`                      | `布尔值`                    | 读取  | 当依赖项已由 SDK 注入时为 True                  |

#### `ConvaiConfigSourceMode` 枚举

| 值        | 说明                            |
| -------- | ----------------------------- |
| `Inline` | 在 Inspector 中直接设置在组件上的配置      |
| `资源`     | 从 `ConvaiCharacterProfile` 资源 |

#### 会话控制

| 方法                                                                                         | 返回值                      | 说明                                                    |
| ------------------------------------------------------------------------------------------ | ------------------------ | ----------------------------------------------------- |
| `StartConversationAsync(CancellationToken ct = default)`                                   | `IConvaiOperation<Unit>` | 为此角色启动一个对话会话                                          |
| `StopConversationAsync(CancellationToken ct = default)`                                    | `IConvaiOperation<Unit>` | 停止此角色的对话会话                                            |
| `WaitForCharacterReadyAsync(float? timeoutSeconds = null, CancellationToken ct = default)` | `IConvaiOperation<Unit>` | 等待角色完成就绪握手。请在以下之后使用 `StartConversationAsync` 在发送输入之前。 |
| `ResetAndRetryAsync(CancellationToken ct = default)`                                       | `IConvaiOperation<Unit>` | 重置角色的会话状态并重试初始化。出错后使用。                                |
| `Reset()`                                                                                  | `布尔值`                    | 同步重置本地会话状态。返回 `是` 如果已应用重置则为 True。                     |

```csharp
// 连接并等待角色就绪后再发送输入
var startOp = character.StartConversationAsync(destroyCancellationToken);
await startOp;
if (startOp.IsSuccessful)
{
    await character.WaitForCharacterReadyAsync(timeoutSeconds: 10f, destroyCancellationToken);
    Debug.Log("Character is ready for input.");
}
```

#### 语音控制

| 方法                    | 返回值                      | 说明                     |
| --------------------- | ------------------------ | ---------------------- |
| `ToggleSpeech()`      | `void`                   | 切换角色的对话会话。断开时启动；连接时停止。 |
| `ToggleSpeechAsync()` | `IConvaiOperation<Unit>` | 的异步版本 `ToggleSpeech`.  |

#### 远程音频控制

| 方法                                    | 返回值    | 说明                                       |
| ------------------------------------- | ------ | ---------------------------------------- |
| `SetRemoteAudioEnabled(bool enabled)` | `布尔值`  | 设置此角色的音频输出是否在本地播放。返回 `是` 如果已应用更改则为 True。 |
| `EnableRemoteAudio()`                 | `布尔值`  | 启用此角色的音频输出。返回 `是` 如果已应用则为 True。          |
| `DisableRemoteAudio()`                | `布尔值`  | 禁用此角色的音频输出。返回 `是` 如果已应用则为 True。          |
| `ToggleRemoteAudio()`                 | `void` | 切换此角色的音频输出状态。                            |

{% hint style="info" %}
按角色控制音频可让你在多角色场景中静音单个角色——例如，在主讲者发言时将次级讲师静音。若要静音麦克风（你的输入），请使用 `ConvaiManager.ActiveManager.Audio`.
{% endhint %}

#### 动态上下文和叙事

| 方法                                                                                          | 返回值    | 说明                                        |
| ------------------------------------------------------------------------------------------- | ------ | ----------------------------------------- |
| `DynamicContext.AddEvent(string text, ConvaiRespondMode reaction = ConvaiRespondMode.Auto)` | `void` | 将按时间顺序的事件附加到角色跟踪的动态上下文中，并向 Convai 准备批量更新。 |
| `SendTrigger(string triggerName)`                                                           | `void` | 按名称调用已保存的 Narrative Design 触发器。           |
| `SendNarrativeEvent(string eventMessage)`                                                   | `void` | 发送内联叙事事件上下文，并让 Convai 自然响应。               |
| `UpdateTemplateKeys(Dictionary<string, string> templateKeys)`                               | `void` | 更新 Narrative Design 模板键值，以用于动态叙事变量替换。     |

{% hint style="info" %}
`SendTrigger` 按名称触发已在 Narrative Design 中配置好的触发器。 `SendNarrativeEvent` 而是发送你在代码中编写的内联消息。请使用最符合事件文本编写位置的方式。
{% endhint %}

#### 注意力和动作

| 方法                                                                                                                               | 返回值                        | 说明                         |
| -------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | -------------------------- |
| `DynamicContext.SetCurrentAttentionObject(object currentAttentionObject, ConvaiRespondMode reaction = ConvaiRespondMode.Silent)` | `void`                     | 按名称或动作对象资源设置角色当前正在关注的场景对象。 |
| `DynamicContext.ClearCurrentAttentionObject(ConvaiRespondMode reaction = ConvaiRespondMode.Silent)`                              | `void`                     | 清除当前场景中的关注对象。              |
| `GetActionConfigSource()`                                                                                                        | `ConvaiActionConfigSource` | 返回此角色的动作配置源组件。             |

#### `ConvaiCharacter` 事件

在以下位置订阅 `OnEnable`，在以下位置取消订阅 `OnDisable`.

| 事件                            | 签名                                           | 触发时                          |
| ----------------------------- | -------------------------------------------- | ---------------------------- |
| `OnTranscriptReceived`        | `Action<string, bool>`                       | 收到转录文本。参数：text, isFinal。     |
| `OnSpeechStarted`             | `Action`                                     | 角色开始产生音频输出                   |
| `OnSpeechStopped`             | `Action`                                     | 角色停止产生音频输出                   |
| `OnTurnCompleted`             | `Action<bool>`                               | 角色的一轮对话结束。参数：wasInterrupted。 |
| `OnCharacterReady`            | `Action`                                     | 角色完成就绪握手                     |
| `OnSessionStateChanged`       | `Action<SessionState>`                       | 此角色的单独会话状态发生变化               |
| `OnEmotionChanged`            | `Action<string, int>`                        | 情绪变化。参数：情绪标签，原始强度（1–3）。      |
| `OnActionsReceived`           | `Action<IReadOnlyList<ConvaiActionCommand>>` | Convai 为此角色发送场景内动作命令         |
| `OnRemoteAudioEnabledChanged` | `Action<bool>`                               | 此角色的远程音频输出已启用或禁用             |

```csharp
using Convai.Runtime.Components;
using UnityEngine;

public class CharacterSessionMonitor : MonoBehaviour
{
    [SerializeField] private ConvaiCharacter _character;

    private void OnEnable()
    {
        _character.OnSessionStateChanged      += OnStateChanged;
        _character.OnRemoteAudioEnabledChanged += OnAudioChanged;
        _character.OnCharacterReady            += OnReady;
    }

    private void OnDisable()
    {
        _character.OnSessionStateChanged      -= OnStateChanged;
        _character.OnRemoteAudioEnabledChanged -= OnAudioChanged;
        _character.OnCharacterReady            -= OnReady;
    }

    private void OnStateChanged(SessionState state) =>
        Debug.Log($"[{_character.CharacterName}] session state: {state}");

    private void OnAudioChanged(bool enabled) =>
        Debug.Log($"[{_character.CharacterName}] audio output: {(enabled ? \"on\" : \"off\")}");

    private void OnReady() =>
        Debug.Log($"[{_character.CharacterName}] ready.");
}
```

***

### `ConvaiPlayer`

`ConvaiPlayer` 表示会话中的本地人类参与者。它拥有玩家的显示名称和身份，并提供文本消息发送功能。

#### 属性

| 属性             | 类型    | 访问 | 说明                |
| -------------- | ----- | -- | ----------------- |
| `PlayerName`   | `字符串` | 读取 | 玩家的显示名称           |
| `PlayerId`     | `字符串` | 读取 | 玩家身份标识符           |
| `NameTagColor` | `颜色`  | 读取 | 用于 UI 中此玩家姓名标签的颜色 |

#### 方法

| 方法                                                     | 返回值    | 说明                                                  |
| ------------------------------------------------------ | ------ | --------------------------------------------------- |
| `SendTextMessage(string message)`                      | `void` | 以该玩家身份向 Convai 发送文本消息，绕过麦克风输入。适用于文本输入模式或程序化玩家对话。    |
| `Configure(string playerName, string playerId = null)` | `void` | 设置玩家的显示名称和可选身份。请在以下之前调用 `ConnectAsync` 以确保会话中使用该身份。 |
| `SetRuntimeDisplayName(string displayName)`            | `void` | 在运行时更新玩家的显示名称，而不更改身份。会反映在转录参与者名称中。                  |

#### `ConvaiPlayer` 事件

| 事件                  | 签名               | 触发时                            |
| ------------------- | ---------------- | ------------------------------ |
| `OnTextMessageSent` | `Action<string>` | 文本消息通过以下方式发送 `SendTextMessage` |

```csharp
using Convai.Runtime.Facades;
using TMPro;
using UnityEngine;

public class TextInputController : MonoBehaviour
{
    [SerializeField] private TMP_InputField _inputField;

    public void OnSubmit()
    {
        var text = _inputField.text.Trim();
        if (string.IsNullOrEmpty(text)) return;

        ConvaiManager.ActiveManager?.Player?.SendTextMessage(text);
        _inputField.text = string.Empty;
    }
}
```

***

### 使用示例

#### 示例 1 — 连接角色并在就绪状态上设置门控

一个医疗培训模拟会确保 AI 医生角色在评估开始前完全就绪，从而防止学习者与尚未初始化的角色对话。

```csharp
using Convai.Runtime.Components;
using Convai.Runtime.Core.Async;
using UnityEngine;

public class AssessmentStarter : MonoBehaviour
{
    [SerializeField] private ConvaiCharacter _physician;
    [SerializeField] private GameObject      _startPanel;

    private async void Start()
    {
        _startPanel.SetActive(false);

        var startOp = _physician.StartConversationAsync(destroyCancellationToken);
        await startOp;
        if (!startOp.IsSuccessful)
        {
            Debug.LogError($"Character connect failed: {startOp.Error.Message}");
            return;
        }

        var readyOp = _physician.WaitForCharacterReadyAsync(
            timeoutSeconds: 15f, destroyCancellationToken);
        await readyOp;

        if (readyOp.IsSuccessful)
            _startPanel.SetActive(true);
        else
            Debug.LogWarning("Character ready timeout — check your API key and network.");
    }
}
```

#### 示例 2 — 多 NPC 场景中的按角色音频切换

一个企业入职模拟包含三位 AI 顾问。一个 UI 面板允许学习者静音任意单个顾问，而不会影响其他顾问。

```csharp
using Convai.Runtime.Components;
using UnityEngine;
using UnityEngine.UI;

public class AdvisorMuteButton : MonoBehaviour
{
    [SerializeField] private ConvaiCharacter _advisor;
    [SerializeField] private Button         _muteButton;
    [SerializeField] private Sprite         _mutedIcon;
    [SerializeField] private Sprite         _unmutedIcon;

    private Image _buttonImage;

    private void Awake() => _buttonImage = _muteButton.GetComponent<Image>();

    private void OnEnable()
    {
        _muteButton.onClick.AddListener(OnToggleMute);
        _advisor.OnRemoteAudioEnabledChanged += RefreshIcon;
        RefreshIcon(_advisor.IsRemoteAudioEnabled);
    }

    private void OnDisable()
    {
        _muteButton.onClick.RemoveListener(OnToggleMute);
        _advisor.OnRemoteAudioEnabledChanged -= RefreshIcon;
    }

    private void OnToggleMute() => _advisor.ToggleRemoteAudio();

    private void RefreshIcon(bool enabled) =>
        _buttonImage.sprite = enabled ? _unmutedIcon : _mutedIcon;
}
```

#### 示例 3 — 用于无障碍访问的文本输入模式

一个工业安全模拟在麦克风访问不可用或受限的环境中提供文本输入备选方案。

```csharp
using Convai.Runtime.Facades;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class AccessibilityTextInput : MonoBehaviour
{
    [SerializeField] private TMP_InputField _inputField;
    [SerializeField] private Button        _submitButton;

    private void OnEnable()  => _submitButton.onClick.AddListener(Submit);
    private void OnDisable() => _submitButton.onClick.RemoveListener(Submit);

    private void Submit()
    {
        var text = _inputField.text.Trim();
        if (string.IsNullOrEmpty(text)) return;

        var player = ConvaiManager.ActiveManager?.Player;
        if (player == null) return;

        player.SendTextMessage(text);
        _inputField.text = string.Empty;
        _inputField.ActivateInputField(); // 保持焦点以便快速输入
    }
}
```

***

### 故障排查

| 症状                                  | 可能原因                                     | 修复方法                                                                                  |
| ----------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------- |
| `WaitForCharacterReadyAsync` 超时     | 角色从未收到来自 Convai 的就绪确认                    | 验证 API 密钥，检查网络；在以下之后调用 `StartConversationAsync` 成功，而不是之前                              |
| `DynamicContext.AddEvent` 没有可见效果    | 在角色进入对话之前调用，因此该事件仅在本地排队，但尚未发送            | 排队的事件会在以下情况时自动发送 `WaitForCharacterReadyAsync` 解析； `DynamicContext.Flush()` 在对话中也只发送一次 |
| `ToggleRemoteAudio()` 没有效果          | `EnableRemoteAudioOnStart` 是 `否` 且音频从未启用 | 调用 `EnableRemoteAudio()` 先激活音频，然后切换                                                   |
| `SendTextMessage` 发送了但角色没有响应        | 会话不在 `已连接` 状态时为 True                     | 检查 `character.IsSessionConnected` 在发送之前                                               |
| `OnActionsReceived` 触发了但没有执行任何场景内动作 | `ConvaiActionDispatcher` 不在场景中或动作名称不匹配   | 验证分发器已存在；动作名称不区分大小写，但必须与已配置名称匹配                                                       |

***

### 下一步

关于房间级别的音频和麦克风控制，请参见 [音频 API](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/scripting-reference/audio-api.md)。关于会话连接控制，请参见 [ConvaiManager API](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/scripting-reference/convaimanager-api.md)。关于通过 relay 或 C# hub 订阅角色事件，请参见 [角色事件](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/scripting-reference/character-events.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, and the optional `goal` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/scripting-reference/character-and-player-api.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.
