> 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/body-animation/usage-examples.md).

# 身体动画使用示例

编写一个角色脚本，使其走向目标并在到达时打招呼、按提示做手势、指向场景对象，并报告自定义行进信息。

这四个场景脚本 `ConvaiBodyAnimationController` 并直接调用其配套组件，适用于需要超出已编写内容之外行为的角色 `ConvaiBodyAnimationSet` 而后端动作会自行触发。每个示例都假设该角色已经有一个可用的 `ConvaiBodyAnimationController` ——参见 [身体动画快速入门](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/body-animation/quick-start.md) 如果还没有的话。

### 走向目标并在到达时打招呼

当场景触发器触发时，一名导游角色会走向一个路径点，然后只有在它确实到达目的地而不是在途中被打断时，才会播放一个打招呼手势。

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

public sealed class GreetOnArrival : MonoBehaviour
{
    [SerializeField] private Transform greetingSpot;

    private ConvaiBodyAnimationController _bodyAnimation;
    private ConvaiNavMeshLocomotion _locomotion;

    private void Awake()
    {
        _bodyAnimation = GetComponent<ConvaiBodyAnimationController>();
        _locomotion = GetComponent<ConvaiNavMeshLocomotion>();
    }

    private void OnEnable() => _locomotion.MoveEnded += OnMoveEnded;
    private void OnDisable() => _locomotion.MoveEnded -= OnMoveEnded;

    public void WalkToGreetingSpot() => _locomotion.MoveTo(greetingSpot.position);

    private void OnMoveEnded(bool reachedDestination)
    {
        if (!reachedDestination) return; // interrupted or stopped short — do not greet

        BodyAnimationActionHandle handle = _bodyAnimation.PlayAction("wave",
            new ActionPlayOptions { HoldSeconds = 2f });
        if (handle.Failed)
            Debug.LogWarning($"Greeting did not play: {handle.FailureReason}");
    }
}
```

`MoveEnded` 报告 `true` 用于一次到达，以及 `false` 用于取消或被中断的移动，因此只有当角色确实到达那里时，问候才会播放。

### 按提示播放手势

当场景逻辑判定受训者做对了什么时，一名训练师角色会点头做出肯定手势，与 Convai 发送的任何内容无关。

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

public sealed class TrainerCues : MonoBehaviour
{
    private ConvaiBodyAnimationController _bodyAnimation;

    private void Awake() => _bodyAnimation = GetComponent<ConvaiBodyAnimationController>();

    public async void PlayAffirmativeCue()
    {
        BodyAnimationActionHandle handle = _bodyAnimation.PlayAction("yes");
        if (handle.Failed)
        {
            Debug.LogWarning($"Affirmative cue did not play: {handle.FailureReason}");
            return;
        }

        bool completedNaturally = await handle.Completion;
        if (!completedNaturally)
            Debug.Log("Affirmative cue was interrupted before it finished.");
    }
}
```

`PlayAction` 从不返回 `null`失败。调用前请检查 `handle.Failed` 而不是进行空值检查——失败的句柄仍会立即完成，因此 `await handle.Completion` 始终可以安全调用。

### 指向场景对象

当玩家询问某个展品时，博物馆导览员会指向该展品三秒，使用展品自身的 `Transform` 因此，如果展品在保持期间移动，手势会重新瞄准。

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

public sealed class PointOutExhibit : MonoBehaviour
{
    [SerializeField] private Transform exhibit;

    private ConvaiBodyAnimationController _bodyAnimation;

    private void Awake() => _bodyAnimation = GetComponent<ConvaiBodyAnimationController>();

    public async void PointAtExhibit()
    {
        BodyAnimationPointingHandle handle = _bodyAnimation.PointAt(exhibit, holdSeconds: 3f);
        if (handle.Failed)
        {
            Debug.LogWarning($"Pointing did not play: {handle.FailureReason}");
            return;
        }

        await handle.Completion;
    }
}
```

`PointAt` 会选择角度上与展品最接近的已编写指向动画片段——参见 [排查身体动画](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/body-animation/troubleshooting.md) 如果手臂始终瞄准偏离目标。

### 从自定义移动器报告移动

过场角色由补间而不是 `ConvaiNavMeshLocomotion`，但在行走时仍需要 Gaze 注视路径。向 `ConvaiTravelIntent` 每一帧报告即可赋予其这种行为，无需涉及 NavMesh。

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

public sealed class TweenMover : MonoBehaviour
{
    [SerializeField] private Transform destination;
    [SerializeField] private float speed = 2f;

    private ConvaiTravelIntent _travelIntent;

    private void Awake()
    {
        _travelIntent = GetComponent<ConvaiTravelIntent>();
        if (_travelIntent == null)
            _travelIntent = gameObject.AddComponent<ConvaiTravelIntent>();
    }

    private void Update()
    {
        Vector3 toDestination = destination.position - transform.position;
        toDestination.y = 0f;

        if (toDestination.magnitude < 0.1f)
        {
            _travelIntent.ClearTravel();
            _travelIntent.ClearSubject();
            return;
        }

        transform.position += toDestination.normalized * speed * Time.deltaTime;
        _travelIntent.ReportTravelTo(destination.position, speed01: 1f);
    }
}
```

`ReportTravelTo` 会报告移动方向并将 `destination` 在一次调用中将其命名为主题，这正是行走时会获得周期性侧目注视的原因。报告刻意不是 NavMesh 功能： `角色控制器`、根运动或第三方导航也是同样的报告方式。停止重复的报告会自行过期，因此不需要单独的“停止”调用，除非 `ClearTravel`.

### 下一步

{% content-ref url="/pages/13dbbe592147612edba60a45974dc24d1b9f3e61" %}
[播放动作和手势](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/body-animation/play-actions-and-gestures.md)
{% endcontent-ref %}

{% content-ref url="/pages/2f6d4e1228a37a16fdb14e3c1941f0d1c8cf7692" %}
[配置移动](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/body-animation/configure-locomotion.md)
{% endcontent-ref %}

{% content-ref url="/pages/3ca8478f323e38c453abf2e41ebd4904fc4a45f6" %}
[身体动画故障排查](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/embodiment/body-animation/troubleshooting.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/body-animation/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.
