> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/tou-xiang/npc-avatars.md).

# NPC 头像

显示并控制 NPC 头像

将头像作为场景中的一个实体显示。

{% hint style="info" %}
**💡 提示**：试试 [NPC Toolkit 库](https://github.com/decentraland-scenes/dcl-npc-toolkit) ，以便更轻松地处理 NPC，尤其是当你需要通过对话树进行交互时。
{% endhint %}

## 创建一个头像

以下代码片段会创建一个带有随机穿戴物和身体形状、名称为“NPC”的头像。

```ts
const myAvatar = engine.addEntity()
AvatarShape.create(myAvatar)

Transform.create(myAvatar, {
	position: Vector3.create(4, 0.25, 5),
})
```

在传递数据以生成 `AvatarShape`时，以下字段是必需的：

* `id`： （必需）Avatar 的内部标识符

此外，还可使用以下可选字段：

* `name`：显示在头像头顶上的名称。默认值：“NPC”。将其设置为空字符串则完全不显示名称，这在你只想显示 [头像名牌](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/tou-xiang/avatar-nametags.md) 板时很有用。
* `bodyShape`：用于定义要使用的身体形状的字符串。有效选项为 'urn:decentraland:off-chain:base-avatars:BaseMale' 和 'urn:decentraland:off-chain:base-avatars:BaseFemale'。
* `wearables`：包含头像当前穿戴物 URN 列表的数组。如果穿戴物冲突（例如两个都是帽子），列表中的最后一个会替换另一个。
* `emotes`：包含头像能够播放的 NFT 表情 URN 列表的数组
* `eyeColor`: *Color3* 用于眼睛颜色（任何颜色都可以）
* `skinColor`: *Color3* 用于肤色（任何颜色都可以）
* `hairColor`: *Color3* 用于头发颜色（任何颜色都可以）
* `说话中`：如果 *true*时，会在名称旁边显示一组绿色条，就像玩家在世界中使用语音聊天时那样。
* <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><strong>💡 提示</strong>：参见 <a href="/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/color-types.md">颜色类型</a> 以了解如何设置颜色的更多详情。</p></div>

{% hint style="warning" %}
**📔 注意**：该 `AvatarShape`组件必须通过以下方式导入：

> `import { AvatarShape } from "@dcl/sdk/ecs"`

参见 [导入](/creator/content-creator-zh/chang-jing-sdk7/ru-men/coding-scenes.md#imports) ，了解如何轻松处理这些内容。
{% endhint %}

{% hint style="warning" %}
**📔 注意**：URN 字段必须遵循与 [NFTShapes](/creator/content-creator-zh/chang-jing-sdk7/mei-ti/display-a-certified-nft.md): `urn:decentraland:<CHAIN>:<CONTRACT_STANDARD>:<CONTRACT_ADDRESS>:<TOKEN_ID>`
{% endhint %}

## 动画

头像在静止时会播放默认的待机动画。

要在头像上播放动画，请将 `expressionTriggerId` 字符串设置为你想播放的动画名称。

```ts
const myAvatar = engine.addEntity()
AvatarShape.create(myAvatar, {
	id: '',
	emotes: [],
	wearables: [],
	expressionTriggerId: 'robot',
})

Transform.create(myAvatar, {
	position: Vector3.create(4, 0.25, 5),
})
```

该 `expressionTriggerId` 字段支持所有 [默认动画](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/tou-xiang/avatar-animations.md#default-animations)，以及来自场景文件的自定义动画 [，甚至还支持来自市场上发布的表情的 URN。](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/tou-xiang/avatar-animations.md#custom-animations)Looping Animations

### 循环动画

动画在 `AvatarShape` 上只会播放一次；如果你希望头像持续循环某个动画，你应该创建一个系统，每隔几秒让它再次播放该动画。

使用 `expressionTriggerTimestamp` 以重新播放同一个表情。此字段的值是一个 [Lamport 时间戳](https://en.wikipedia.org/wiki/Lamport_timestamp)，这意味着它不是时间值，而是一个每次表情重复时都会加 1 的索引。

因此，当你第一次播放一个表情时，你会设置 `expressionTriggerTimestamp` 为 *0*。要再次播放该表情，你必须将此值更新为 1。这就是引擎识别这是一个新指令，而不是它已经执行过的指令的方式。

以下代码片段创建了一个每 2 秒运行一次同样表情的系统：

```ts
const myAvatar = engine.addEntity()
AvatarShape.create(myAvatar, {
	id: '',
	emotes: [],
	wearables: [],
	expressionTriggerId: 'clap',
    expressionTriggerTimestamp: 0
})

Transform.create(myAvatar, {
	position: Vector3.create(4, 0.25, 5),
})

let clapTimer = 0
let emoteDuration = 2  // 2 seconds

// system
engine.addSystem((dt: number) => {
    clapTimer += dt
      
    if (clapTimer >= emoteDuration) {
        // Trigger the clap emote
        AvatarShape.getMutable(myAvatar).expressionTriggerTimestamp += 1
        
        clapTimer = 0 // Reset timer
    }
})
```

{% hint style="info" %}
**💡 提示**：你必须知道表情的持续时间，并将其作为系统的持续时间。如果你创建了一个会让头像固定保持同一姿势的表情，建议将该表情的持续时间设得比系统更长。这样，你就可以确保在结束并重置动画时不会出现瑕疵。
{% endhint %}

## 在名称上方添加标签

使用 `头像名牌` 组件可在 NPC 名称上方显示带有自定义文本的牌子，例如“Shopkeeper”或“Boss”之类的角色。将其附加到具有 `AvatarShape`:

```ts
AvatarNametag.create(myAvatar, { label: 'Shopkeeper' })
```

如果 `AvatarShape` 具有空的 `name`，则只显示牌子，不会在其下方显示空的名牌框。这对于仅用头衔给 NPC 标注很方便。

{% hint style="info" %}
**💡 提示**：若要显示一个无文本的颜色标识牌，请设置 `label` 设置为空格字符串，并选择一个 `backgroundColor`。空格会被保留，因此更多空格会让牌子更宽。

```ts
AvatarNametag.create(myAvatar, {
	label: '      ',
	backgroundColor: Color3.Red(),
})
```

{% endhint %}

参见 [头像名牌](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/tou-xiang/avatar-nametags.md) 以查看包括颜色在内的完整字段列表。

## 从玩家复制穿戴物

以下代码片段会将 NPC 头像的穿戴物和其他特征更改为与玩家当前穿戴的内容相匹配。这可以在场景中用作人体模特，以展示特定的穿戴物或表情，并与玩家当前的装扮组合展示。

```ts
import { getPlayer } from '@dcl/sdk/src/players'


export function swapAvatar(avatar: Entity) {

  let userData = getPlayer()
  console.log(userData)

  if (!userData || !userData.wearables) return

  const mutableAvatar = AvatarShape.getMutable(avatar)

  mutableAvatar.wearables = userData.wearables
  mutableAvatar.bodyShape = userData.avatar?.bodyShapeUrn
  mutableAvatar.eyeColor = userData.avatar?.eyesColor
  mutableAvatar.skinColor = userData.avatar?.skinColor
  mutableAvatar.hairColor = userData.avatar?.hairColor
  
}
```

## 仅显示穿戴物

使用 `showOnlyWearables` 字段，用于仅显示头像列出的穿戴物。头像其余部分将不可见。

```ts
const myAvatar = engine.addEntity()
AvatarShape.create(myAvatar, {
	id: '',
	emotes: [],
	wearables: [
    'urn:decentraland:matic:collections-v2:0x90e5cb2d673699be8f28d339c818a0b60144c494:0'
  ],
	showOnlyWearables: true,
})

Transform.create(myAvatar, {
	position: Vector3.create(4, 0.25, 5),
})
```

这对于展示穿戴物很有用，例如在商店中。

{% hint style="info" %}
**💡 提示**：如果某个穿戴物比较小，尝试将 `缩放` 的 `Transform` 设置为更大的值。
{% endhint %}

## 将实体附加到 NPC

你可以使用 `AvatarAttach` 功能将一个实体固定到 NPC 头像的某块骨骼上，例如让 NPC 手里拿着一个物体。该实体在动画播放时会随头像一起移动。

要使用此功能，请使用 `id` 属性在任何 UI 实体上的 `AvatarShape` 为此头像分配一个任意 id，然后在 `AvatarAttach`上引用该 id。这个 id 可以是任意字符串。

```ts
// 创建 NPC，带有一个 ID
const myAvatar = engine.addEntity()
Transform.create(myAvatar, {
  position: Vector3.create(8, 0.25, 8),
})
AvatarShape.create(myAvatar, {
  id: "my-avatar-id", 
  wearables: [],
  emotes: []
})

// 创建要附加到 NPC 的对象
const attachedEntity = engine.addEntity()
Transform.create(attachedEntity, {
    position: Vector3.create(4, 2, 4),
    scale: Vector3.create(0.15,0.15,0.15)
})
MeshRenderer.setBox(attachedEntity)
Material.setBasicMaterial(attachedEntity, { diffuseColor: Color4.Blue() })
AvatarAttach.create(attachedEntity, {
    avatarId: "my-avatar-id",
    anchorPointId: AvatarAnchorPointType.AAPT_LEFT_HAND
})
```

了解更多关于 `AvatarAttach` 组件 [这里](/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/entity-positioning.md#attach-an-entity-to-an-avatar).

## 替换玩家头像

你不能更改玩家头像所穿戴的物品，但可以改为将玩家头像替换为一个你可以完全自定义的 NPC 头像。

要做到这一点，请使用一个 [头像修改区域](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/tou-xiang/modifier-areas.md#hide-avatars) ，并使用 `AMT_HIDE_AVATARS` 修饰符隐藏玩家自己的头像，然后改为在玩家的位置显示一个 `AvatarShape` 实体。

{% hint style="warning" %}
**📔 注意**：要让玩家对该头像拥有完全控制权，你应监听按钮事件，以检测他们何时按下按钮，然后在 NPC 头像上触发相应的动画。参见 [按钮事件](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/system-based-events.md) 了解更多详情。

在这样做时，控制的流畅性可能不会完美，因此你可能只想在非常特定的情况下使用它。
{% endhint %}


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/tou-xiang/npc-avatars.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
