> 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/embodiment/emotion/usage-examples.md).

# 情绪示例

七个完整场景，涵盖危险覆盖、锁定表情、心情转换、痛苦分支、分析日志以及无代码 UI 连接。

这些场景展示了 Emotion 系统的配置和脚本 API 如何结合起来满足真实的应用需求。每个场景都是自包含的：先描述 Inspector 设置，然后给出完成该行为所需的任何运行时代码。配置文件字段引用见 [情绪配置文件](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/emotion-profile.md)；完整脚本接口见 [情绪脚本 API](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/scripting-api.md).

### 场景 1：动态危险响应

**情境：** 一名讲师 NPC 引导受训者完成消防疏散模拟。当受训者进入标记的危险区域时，讲师的表情应迅速转为恐惧或紧迫，以强化情境的严肃性。当受训者离开该区域时，表情恢复为服务器驱动的状态。

#### 配置文件设置

打开 `ConvaiEmotionProfile` 分配给讲师 NPC 并调整：

* **`lerpSpeed`** → `12` ——快速上升，使恐惧表情立即呈现。
* **`microBurstOvershoot`** → `1.6` ——明显的突增让过渡更具视觉冲击力。
* **`microBurstDuration`** → `0.2 s` ——在表情稳定前的短暂突发。

#### 运行时脚本

```csharp
using Convai.Modules.Emotion.Components;
using UnityEngine;

public sealed class HazardZoneTrigger : MonoBehaviour
{
    [SerializeField] private ConvaiEmotionController instructorEmotion;

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Trainee"))
            instructorEmotion.SetEmotionOverride("fear", 0.9f);
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Trainee"))
            instructorEmotion.ClearEmotionOverride();
    }
}
```

`SetEmotionOverride` 会在 Convai 当前发送的内容之上叠加恐惧分数。累加器会在配置的 `lerpSpeed`，因此覆盖会快速但自然地到达。 `ClearEmotionOverride` 在触发器退出时调用，可让服务器发出恢复完全控制的信号。角色本身无需逐槽编写——表情配方会自动解析 `"fear"` 并映射到角色的骨骼绑定上。

***

### 场景 2：锁定的欢迎表情

**情境：** 一名迎宾 NPC 站在入门引导模拟的入口。在欢迎流程期间——在受训者开始说话之前——无论 Convai 在连接握手期间发送任何情绪信号，角色都应始终显得温暖且易于接近。

#### 运行时脚本

```csharp
using Convai.Modules.Emotion.Components;
using UnityEngine;

public sealed class WelcomeSequenceController : MonoBehaviour
{
    [SerializeField] private ConvaiEmotionController greeterEmotion;

    private void Start()
    {
        // 从第一帧开始保持一个温和、欢迎的表情
        greeterEmotion.LockEmotion("joy", 0.65f);
    }

    public void OnWelcomeSequenceComplete()
    {
        // 释放锁定，使角色能自然地对对话做出反应
        greeterEmotion.UnlockEmotion();
    }
}
```

锁定的强度为 `0.65` 会产生一个可见但不过度夸张的微笑——适合专业场景。 `UnlockEmotion` 会在模拟切换到开放对话时调用，此时角色开始响应实时 AI 信号。

***

### 场景 3：会话中逐渐变得更温暖的角色

**情境：** 客户服务培训 NPC 应该在每个会话开始时保持中性、专业的静息情绪，并在受训者把对话处理得很好时明显地逐渐变得更温暖——这是培训师之后可以指给人看的静息情绪变化，区别于对话过程中任何瞬时反应。

#### 运行时脚本

```csharp
using Convai.Modules.Emotion.Components;
using UnityEngine;

public sealed class RapportDirector : MonoBehaviour
{
    [SerializeField] private ConvaiEmotionController trainerEmotion;
    [SerializeField] private int goodExchangeCount;
    private const int WarmupThreshold = 3;

    public void OnExchangeScoredWell()
    {
        goodExchangeCount++;
        if (goodExchangeCount == WarmupThreshold)
            trainerEmotion.SetMood("joy", 0.5f, transitionSeconds: 4f);
    }

    public void OnSessionReset()
    {
        goodExchangeCount = 0;
        trainerEmotion.ClearMood();
    }
}
```

`SetMood` 会改变角色的 **静息情绪** ——表情在瞬时反应之间回落到的情绪——而不是注入一次性的表情。四秒的过渡会被理解为逐渐升温，而不是突然的情绪波动。 `ClearMood` 在会话重置时会将角色恢复到其预设基线。参见 [情绪状态](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/moods.md) ，了解静息情绪与瞬时情绪的区别，以及 [情绪脚本 API](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/scripting-api.md#runtime-mood-control) 完整的优先级规则。

***

### 场景 4：情绪感知分支逻辑

**情境：** 医疗沟通评估中的虚拟患者 NPC 会在受训者的回应被视为敷衍时变得沮丧。一个导演脚本监视该 NPC 的情绪状态，如果检测到持续的沮丧，就将场景分支到缓和路径。

#### 运行时脚本

```csharp
using Convai.Domain.Embodiment.Readings;
using Convai.Modules.Emotion.Components;
using UnityEngine;
using UnityEngine.Events;

public sealed class EmotionBranchDirector : MonoBehaviour
{
    [SerializeField] private ConvaiEmotionController patientEmotion;
    [SerializeField] private float distressThreshold = 0.6f;
    [SerializeField] private float sustainedDistressSeconds = 4f;
    [SerializeField] private UnityEvent onDistressBranchTriggered;

    private bool _branchTriggered;

    private void Update()
    {
        if (_branchTriggered) return;

        EmotionReading reading = patientEmotion.Current;

        bool isSadOrFearful = reading.DominantLabel is "sadness" or "fear"
                              && reading.DominantScore >= distressThreshold;

        if (isSadOrFearful && reading.DominantHoldSeconds >= sustainedDistressSeconds)
        {
            _branchTriggered = true;
            onDistressBranchTriggered.Invoke();
        }
    }
}
```

`DominantHoldSeconds` 用于跟踪当前主导情绪已持续保持了多长时间。将它与分数阈值一起使用，可以防止瞬时峰值触发分支——只有真正持续的沮丧才会推进场景。

***

### 场景 5：会话分析日志记录

**情境：** 培训平台需要记录 AI 角色在会话中经历的每一次情绪变化，包括原始服务器标签和强度，以便讲师在会话后报告中回顾对话的情绪轨迹。

#### 运行时脚本

```csharp
using Convai.Domain.DomainEvents.Runtime;
using Convai.Runtime.Components;
using System.Collections.Generic;
using UnityEngine;

public sealed class EmotionSessionLogger : MonoBehaviour
{
    [SerializeField] private ConvaiManager convaiManager;

    private readonly List<string> _emotionLog = new();

    private void OnEnable()
    {
        convaiManager.Events.OnCharacterEmotionChanged += HandleEmotionChanged;
    }

    private void OnDisable()
    {
        convaiManager.Events.OnCharacterEmotionChanged -= HandleEmotionChanged;
    }

    private void HandleEmotionChanged(CharacterEmotionChanged e)
    {
        string entry = $"[{e.Timestamp:HH:mm:ss.fff}] {e.CharacterId}: {e.Emotion} (scale {e.Intensity})";
        _emotionLog.Add(entry);
        Debug.Log(entry);
    }

    public IReadOnlyList<string> GetLog() => _emotionLog;
}
```

`OnCharacterEmotionChanged` 会在来自 Convai 的每一条情绪信号上触发，而且是在控制器对其进行平滑或处理之前触发。这使分析代码能够访问原始信号，而不是插值后的视觉状态，这对于会话回顾更有意义。如果你想记录角色最终实际表现出来的内容，请订阅 `DominantEmotionChanged`/`MoodChanged` ——参见 [情绪脚本 API](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/scripting-api.md#resolved-emotion-and-mood-events).

***

### 场景 6：无代码 UI 显示

**情境：** 某个非程序员希望在角色当前情绪变化时更新显示该情绪的 UI 标签，而无需编写任何代码。

{% stepper %}
{% step %}

#### 添加事件中继

选择 NPC 的根 GameObject。点击 **Add Component** 并导航到 **Convai → Events → Convai Character Event Relay**.

中继会自动解析 `ConvaiCharacter` 同一 GameObject 上的，借助 **Auto Resolve Character** 切换开关完成，默认已启用。
{% endstep %}

{% step %}

#### 连接 On Emotion Changed 事件

在 **On Emotion Changed** 在以下对象的 Unity Event 列表中 `ConvaiCharacterEventRelay`，点击 **+**.
{% endstep %}

{% step %}

#### 分配 UI Text 组件

拖动你的 UI `Text` （或 `TMP_Text`）组件到新事件条目的对象字段中。
{% endstep %}

{% step %}

#### 选择目标属性

在函数下拉菜单中选择 **Text → string text** （或 **TMP\_Text → string text**).

现在每当角色的情绪变化时， `情绪` 来自 `CharacterEmotionRelayData` 的属性会直接写入标签——无需代码。
{% endstep %}
{% endstepper %}

{% hint style="success" %}
进入 Play Mode 并与角色对话。随着 Convai 发送新的情绪信号，UI 标签会自动更新。
{% endhint %}

`ConvaiCharacterEventRelay` 会传递原始服务器标签（例如 `"happy"`）。如果你需要更友好的显示名称（例如 `"喜悦"` 而不是 `"happy"`），可添加一个小型格式化脚本，将原始标签映射为显示字符串，或者在 UnityEvent 目标方法中对该字符串进行后处理。

***

### 场景 7：在编辑器中预览表情

**情境：** 你已经为角色配置了骨骼绑定，并希望在进入 Play Mode 之前确认每种情绪是否能驱动出可识别的表情。

1. 选择 NPC 的根 GameObject。
2. 在 `ConvaiEmotionController` 组件上，启用 **锁定情绪**.
3. 将 **锁定情绪标签** 为你想预览的规范标签（例如 `"anger"`).
4. 将 **锁定强度** 到 `1.0`.

Scene 视图会立即更新——由于 `ConvaiEmotionController` 继承自 `[ExecuteAlways]` 其基类，表情配方会在编辑模式下解析并应用。你可以在你的分类法中轮流切换各个标签，以可视化方式验证每个表情，或者使用 [情绪编辑器窗口](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/emotion-editor.md) 在打开的场景中对每个角色进行引导式预览。

{% hint style="danger" %}
将 **锁定情绪** 切换回 `false` 在为生产环境构建之前。该字段会被序列化——如果它保持启用状态，那么在发布版本中角色会忽略所有后端情绪信号，并且不会出现运行时错误或警告。
{% endhint %}

### 下一步

有关上述配置文件设置中使用的完整参数参考，请参见 [情绪配置文件](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/emotion-profile.md)。有关完整脚本接口，请参见 [情绪脚本 API](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/scripting-api.md)。如果任何场景未产生预期结果，请参见 [情绪故障排查](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/troubleshooting-and-diagnostics.md).

{% content-ref url="/pages/5a9247365092d958f2d539ae98bdfe69f72df091" %}
[Emotion 配置文件](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/emotion-profile.md)
{% endcontent-ref %}

{% content-ref url="/pages/39d161d99d04e6ca98725c740d134ccb5eac9e73" %}
[Emotion 脚本 API](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/scripting-api.md)
{% endcontent-ref %}

{% content-ref url="/pages/65ec9decd2473b72bc06bf3c946f3008c8528dda" %}
[排查情绪问题](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/emotion/troubleshooting-and-diagnostics.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/embodiment/emotion/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.
