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

#### 属性

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

#### `ConvaiConfigSourceMode` 枚举

| 值    | 描述                              |
| ---- | ------------------------------- |
| `内联` | 在 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>` | 重置角色的会话状态并重试初始化。在出现错误后使用。                               |
| `重新发送；只会清除运行时跟踪的状态和事件。`                                                                    | `bool`                   | 同步重置本地会话状态。返回 `true` 如果重置已应用。                           |

```csharp
// 连接并等待角色就绪后再发送输入
var startOp = character.StartConversationAsync(destroyCancellationToken);
await startOp;
if (startOp.IsSuccessful)
{
    await character.WaitForCharacterReadyAsync(timeoutSeconds: 10f, destroyCancellationToken);
    Debug.Log("角色已准备好接收输入。");
}
```

#### 语音控制

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

#### 远程音频控制

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

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

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

| 方法                                                              | 返回     | 描述                                               |
| --------------------------------------------------------------- | ------ | ------------------------------------------------ |
| `SendDynamicInfo(string contextText)`                           | `void` | 向 Convai 发送此角色的动态上下文更新。无需重新连接即可更新角色会话内的上下文。      |
| `SendTrigger(string triggerName, string triggerMessage = null)` | `void` | 按名称发送叙事设计触发器。 `triggerMessage` 如果提供，则覆盖触发器配置的消息。 |
| `UpdateTemplateKeys(Dictionary<string, string> templateKeys)`   | `void` | 更新叙事设计模板键值，用于动态叙事变量替换。                           |

#### 注意力与动作

| 方法                                                                                              | 返回                         | 描述                       |
| ----------------------------------------------------------------------------------------------- | -------------------------- | ------------------------ |
| `SetCurrentAttentionObject(string objectName, string runLlm = "false")`                         | `void`                     | 按名称设置角色当前关注的场景对象。        |
| `SetCurrentAttentionObject(ConvaiActionObjectDefinition actionObject, string runLlm = "false")` | `void`                     | 使用已定义的动作对象资源设置场景内的注意力对象。 |
| `ClearCurrentAttentionObject(string runLlm = "false")`                                          | `void`                     | 清除当前场景内的注意力对象。           |
| `GetActionConfigSource()`                                                                       | `ConvaiActionConfigSource` | 返回此角色的动作配置源组件。           |

#### `ConvaiCharacter` 事件

订阅于 `OnEnable`，取消订阅于 `OnDisable`.

| 事件                            | 签名                                           | 触发于                          |
| ----------------------------- | -------------------------------------------- | ---------------------------- |
| `OnTranscriptReceived`        | `Action<string, bool>`                       | 转录到达。参数：text, isFinal。       |
| `OnSpeechStarted`             | `动作`                                         | 角色开始产生音频输出                   |
| `OnSpeechStopped`             | `动作`                                         | 角色停止产生音频输出                   |
| `OnTurnCompleted`             | `Action<bool>`                               | 角色的对话轮次结束。参数：wasInterrupted。 |
| `OnCharacterReady`            | `动作`                                         | 角色完成其就绪握手                    |
| `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}] 会话状态：{state}");

    private void OnAudioChanged(bool enabled) =>
        Debug.Log($"[{_character.CharacterName}] 音频输出：{(enabled ? "开" : "关")}");

    private void OnReady() =>
        Debug.Log($"[{_character.CharacterName}] 已准备就绪。");
}
```

***

### `ConvaiPlayer`

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

#### 属性

| 属性             | 类型      | 访问 | 描述                |
| -------------- | ------- | -- | ----------------- |
| `PlayerName`   | `字符串`   | 阅读 | 玩家的显示名称           |
| `PlayerId`     | `字符串`   | 阅读 | 玩家身份标识符           |
| `NameTagColor` | `Color` | 阅读 | 用于 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($"角色连接失败：{startOp.Error.Message}");
            return;
        }

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

        if (readyOp.IsSuccessful)
            _startPanel.SetActive(true);
        else
            Debug.LogWarning("角色就绪超时——请检查你的 API 密钥和网络。");
    }
}
```

#### 示例 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` 成功，而不是之前 |
| `SendDynamicInfo` 没有明显效果         | 在角色会话连接之前调用                                  | 在以下之后调用 `WaitForCharacterReadyAsync` 成功解析                |
| `ToggleRemoteAudio()` 没有效果       | `EnableRemoteAudioOnStart` 为 `false` 且音频从未启用 | 调用 `EnableRemoteAudio()` 先激活音频，然后切换                      |
| `SendTextMessage` 已发送但角色没有响应     | 会话不在 `Connected` 状态                          | 检查 `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:

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

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.
