> 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/player-avatar.md).

# 玩家头像

了解如何控制玩家头像

你可以通过多种方式控制玩家的头像，并为你的玩家改变游戏体验。

有关处理非玩家头像，请参见 [NPC 头像](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/npc-avatars.md).

## 移动玩家

{% hint style="info" %}
**💡 提示**：移动玩家最简单的方法是使用 [Creator Hub 中的场景编辑器](/creator/content-creator-zh/chang-jing-bian-ji-qi/kai-shi-shi-yong/about-editor.md)。使用无代码的 **移动玩家** 或 **将玩家移动到这里** 操作，请参见 [让任意项目变为智能项目](/creator/content-creator-zh/chang-jing-bian-ji-qi/jiao-hu-xing/make-any-item-smart.md).
{% endhint %}

要更改玩家在场景中的位置，请使用 `movePlayerTo()` 函数。该函数接收一个包含三个属性的对象：

* `newRelativePosition`：玩家要被放置的位置，以 Vector3 表示。
* `cameraTarget`：可选。让摄像机朝向的方向，以 Vector3 表示，即要看的空间中某个点的坐标。如果未提供值，摄像机将保持与移动前相同的旋转。
* `avatarTarget`：可选。让头像朝向的方向，以 Vector3 表示，即要看的空间中某个点的坐标。如果未提供值，头像将保持与移动前相同的旋转。如果玩家处于第一人称摄像机模式，摄像机和头像的旋转是相同的。
* `持续时间`：可选。过渡应持续的时间，单位为秒。如果未提供值，过渡将立即发生。如果提供了持续时间，头像将步行或跑步到这个新位置。

{% hint style="warning" %}
**📔 注意**：在过渡期间，头像不受碰撞体影响，因此可以穿过物体。
{% endhint %}

```ts
import { movePlayerTo } from '~system/RestrictedActions'

// 创建实体
const myEntity = engine.addEntity()
MeshRenderer.setBox(myEntity)
MeshCollider.setBox(myEntity)

Transform.create(myEntity, {
	position: { x: 4, y: 1, z: 4 },
})

// 赋予实体行为
pointerEventsSystem.onPointerDown(
	{
		entity: myEntity,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Click' },
	},
	function () {
		// 让玩家重生
		movePlayerTo({
			newRelativePosition: Vector3.create(1, 0, 1),
			cameraTarget: Vector3.create(8, 1, 8),
			avatarTarget: Vector3.create(8, 1, 8),
		})
	}
)
```

玩家的移动会立即发生，不会出现任何确认界面或摄像机过渡。

{% hint style="warning" %}
**📔 注意**：只有当玩家已经站在场景边界内时才能移动，而且只能移动到场景边界限制范围内的位置。你不能使用 `movePlayerTo()` 将玩家传送到另一个场景。要将玩家移动到另一个场景，请参见 [传送](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/external-links.md#teleports).
{% endhint %}

该 `movePlayerTo()` 函数是可等待的，因此如果移动有持续时间，你可以使用 `await` 来等待玩家到达目的地。

```ts
import { movePlayerTo } from '~system/RestrictedActions'

pointerEventsSystem.onPointerDown(
	{
		entity: myEntity,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Click' },
	},
	async function () {
		await movePlayerTo({
			newRelativePosition: Vector3.create(1, 0, 1),
			cameraTarget: Vector3.create(8, 1, 8),
			avatarTarget: Vector3.create(8, 1, 8),
			duration: 2,
		})
	}
)
```

如果玩家在过渡持续期间尝试移动，过渡将被中断，而 `movePlayerTo` 函数将永远不会返回解析结果。你可以通过在过渡进行时使用 `InputModifier` 组件，参见 [限制移动方式](#restrict-locomotion).

```ts
import { movePlayerTo } from '~system/RestrictedActions'
import {InputModifier, engine} from '@dcl/sdk/ecs'

pointerEventsSystem.onPointerDown(
	{
		entity: myEntity,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Click' },
	},
	async function () {

		// 禁用所有输入
		InputModifier.create(engine.PlayerEntity, {
			mode: InputModifier.Mode.Standard({
				disableAll: true,
			}),
		})

		// 移动玩家
		await movePlayerTo({
			newRelativePosition: Vector3.create(1, 0, 1),
			cameraTarget: Vector3.create(8, 1, 8),
			avatarTarget: Vector3.create(8, 1, 8),
			duration: 2,
		})

		// 启用所有输入
		InputModifier.deleteFrom(engine.PlayerEntity)
	}
)
```

{% hint style="warning" %}
**📔 注意**：此外，await 的结果还可以存储起来，以评估其 `成功` 属性，从而判断移动是被中断了（例如被输入移动打断），还是成功完成了。
{% endhint %}

## 播放动画

你可以让玩家在场景代码中执行动画。这有助于增强沉浸感，也有助于让其他玩家彼此了解对方在做什么。头像动画会同时被玩家自己（第三人称视角）以及周围的其他玩家看到。

由玩家控制的、作用于全身的动画会被默认的移动动画覆盖，比如行走和跳跃。因此，场景播放的全身动画只会在玩家站立不动时播放。如果玩家行走或跳跃，任何全身动画都会被中断。上半身动画不会被移动打断。

{% hint style="warning" %}
**📔 注意**：只有当玩家已经站在场景边界内时才能播放动画，而不能在相邻场景中播放。智能穿戴物可以在任何地方播放动画。

当玩家正在执行动画时，他们不受碰撞影响，移动也不受场景物理规则限制。另外请注意，如果动画使玩家偏离其原始位置（例如动画包含跳跃），玩家的 Transform 组件不会受到这种位移的影响。
{% endhint %}

### 使用场景编辑器

让玩家执行动画的最简单方法是使用场景编辑器。使用无代码的 **播放表情动作** 操作播放默认动画，或使用 **播放自定义表情动作** 操作播放文件中的动画。请参见 [让任意项目变为智能项目](/creator/content-creator-zh/chang-jing-bian-ji-qi/jiao-hu-xing/make-any-item-smart.md).

### 默认动画

使用 `triggerEmote()` 函数来运行玩家可以在 Decentraland 任意地点播放的默认动画之一。该函数接收一个包含以下属性的对象作为参数：

* `predefinedEmote`：现有表情的字符串名称。
* `mask`：可选。使用 `AvatarMask` 枚举中的值，只在头像身体的部分区域播放动画。例如， `AvatarMask.AM_UPPER_BODY` 只会为头像的上半身播放动画。请参见 [仅为上半身播放动画](#animate-only-the-upper-body).

```ts
import { triggerEmote } from '~system/RestrictedActions'

const emoter = engine.addEntity()
Transform.create(emoter, { position: Vector3.create(8, 0, 8) })
MeshRenderer.setBox(emoter)
MeshCollider.setBox(emoter)
pointerEventsSystem.onPointerDown(
	{
		entity: emoter,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Dance' },
	},
	() => {
		triggerEmote({ predefinedEmote: 'robot' })
	}
)
```

以下表情会反馈你场景中玩家的动作，这些都可以作为 `predefinedEmote` 字段的有效值：

* `buttonDown`
* `buttonFront`
* `getHit`
* `knockOut`
* `lever`
* `openChest`
* `openDoor`
* `punch`
* `push`
* `swingWeaponOneHand`
* `swingWeaponTwoHands`
* `throw`
* `sittingChair1`
* `sittingChair2`
* `sittingGround1`
* `sittingGround2`

这些表情在所有玩家的默认表情轮盘中都可用，也可以在任何场景中使用。

* `wave`
* `fistpump`
* `robot`
* `raiseHand`
* `clap`
* `money`
* `kiss`
* `tik`
* `hammer`
* `tektonik`
* `dontsee`
* `handsair`
* `shrug`
* `disco`
* `dab`
* `headexplode`

{% hint style="info" %}
**💡 提示**：如果玩家在播放动画时行走或跳跃，他们会中断动画。如果你不希望这种情况发生，你可以在头像动画持续期间使用 [输入修饰器](#freeze-the-player) 来冻结头像。
{% endhint %}

### 自定义动画

使用 `triggerSceneEmote()` 让玩家执行自定义动画，该动画作为场景资产的一部分存储为 .glb 文件。

{% hint style="warning" %}
**📔 注意**：文件名 **必须** 必须以 `_emote.glb` 结尾，才能作为头像动画工作。
{% endhint %}

该函数接收一个包含以下属性的对象：

* `src`：指向表情文件路径的字符串。
* `loop`：如果为 true，动画将持续循环，直到玩家移动或动画停止。默认值为 false。
* `mask`：可选。使用 `AvatarMask` 枚举中的值，只在头像身体的部分区域播放动画。例如， `AvatarMask.AM_UPPER_BODY` 只会为头像的上半身播放动画。请参见 [仅为上半身播放动画](#animate-only-the-upper-body).

```ts
import { triggerSceneEmote } from '~system/RestrictedActions'
import { AvatarMask } from '@dcl/sdk/ecs'

const emoter = engine.addEntity()
Transform.create(emoter, { position: Vector3.create(8, 0, 8) })
MeshRenderer.setBox(emoter)
MeshCollider.setBox(emoter)
pointerEventsSystem.onPointerDown(
	{
		entity: emoter,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Make snowball' },
	},
	() => {
		triggerSceneEmote({ src: 'animations/Snowball_Throw_emote.glb', loop: false, mask: AvatarMask.AM_UPPER_BODY })
	}
)
```

{% hint style="info" %}
**💡 提示**：如果玩家在播放动画时行走或跳跃，他们会中断动画。如果你不希望这种情况发生，你可以在头像动画持续期间使用 [输入修饰器](#freeze-the-player) 来冻结头像。
{% endhint %}

### 仅为上半身播放动画

两者都 `triggerEmote()` 和 `triggerSceneEmote()` 都可接受一个可选的 `mask` 属性，用于将动画限制在头像身体的部分区域。

通常情况下，一旦玩家行走或跳跃，动画就会停止，因为默认的移动动画会接管整个身体。当你设置 `mask` 为 `AvatarMask.AM_UPPER_BODY`时，动画只会驱动头像腰部以上的部分，而腿部仍由默认的移动动画控制。这意味着玩家可以在场景中继续行走或奔跑，同时上半身播放你的动画。可将其用于不应中断移动的动作，例如搬运箱子、举着火炬或杂耍。

```ts
import { triggerSceneEmote } from '~system/RestrictedActions'
import {
	engine,
	AvatarMask,
	InputAction,
	MeshCollider,
	MeshRenderer,
	pointerEventsSystem,
	Transform,
} from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const cheerButton = engine.addEntity()
Transform.create(cheerButton, { position: Vector3.create(8, 0, 8) })
MeshRenderer.setBox(cheerButton)
MeshCollider.setBox(cheerButton)
pointerEventsSystem.onPointerDown(
	{
		entity: cheerButton,
		opts: { button: InputAction.IA_POINTER, hoverText: 'Cheer' },
	},
	() => {
		triggerSceneEmote({
			src: 'animations/Cheer_emote.glb',
			loop: true,
			mask: AvatarMask.AM_UPPER_BODY,
		})
	}
)
```

在这个例子中，玩家点击一个按钮，并开始双臂高举地欢呼，且是循环动画。由于只会播放上半身动画，他们可以在欢呼的同时继续在场景中奔跑，例如追随比赛或足球赛中的动作。

需要记住的几点：

* `AvatarMask.AM_UPPER_BODY` 目前是 `AvatarMask` 枚举中的唯一值。要播放全身动画，只需不要设置 `mask` 属性。
* 该 `loop` 属性的行为与全身动画相同：当 `loop: false` 时，带遮罩的动画会播放一次，然后上半身恢复为正常移动；当 `loop: true` 时，它会重复播放，直到停止。
* 要通过代码停止一个循环播放的带遮罩动画，请调用 `stopEmote({})`，它同样从 `~system/RestrictedActions`.

### 检测表情何时结束

每个表情生命周期事件都会通过玩家实体上的 `AvatarEmoteCommand` 组件进行报告。每个新条目都带有一个 `state` 字段，其值来自 `EmoteState` 枚举：

* `EmoteState.ES_STARTED`：表情开始播放。当 `state` 字段缺失时，也会报告这个值（由旧客户端写入的条目）。
* `EmoteState.ES_FINISHED`：一个不循环的表情已自然播放完毕。
* `EmoteState.ES_INTERRUPTED`：表情被提前中断：玩家移动或跳跃、传送、开始了另一个表情、表情被显式停止，或者玩家离开了场景。

这适用于由场景触发的表情（`triggerEmote()` 和 `triggerSceneEmote()`）以及玩家通过表情轮盘自行播放的表情，也适用于场景中其他玩家播放的表情。

使用 `onChange` 函数在 `AvatarEmoteCommand` 组件上可用于响应每个新条目：

```ts
import { AvatarEmoteCommand, EmoteState } from '@dcl/sdk/ecs'

export function main() {
	AvatarEmoteCommand.onChange(engine.PlayerEntity, (emote) => {
		if (!emote) return

		switch (emote.state ?? EmoteState.ES_STARTED) {
			case EmoteState.ES_STARTED:
				console.log('表情开始：', emote.emoteUrn)
				break
			case EmoteState.ES_FINISHED:
				console.log('表情自然结束：', emote.emoteUrn)
				break
			case EmoteState.ES_INTERRUPTED:
				console.log('表情被中断：', emote.emoteUrn)
				break
		}
	})
}
```

{% hint style="warning" %}
**📔 注意**：此功能目前仅支持桌面客户端。使用 `mask` 在本地玩家身上播放的表情（部分身体表情）目前不会报告生命周期事件。
{% endhint %}

## 限制移动方式

你可以限制玩家在你的场景中可以执行的操作。可用它来冻结玩家，或限制特定形式的移动，例如阻止玩家跳跃或奔跑。

### 冻结玩家

你可以冻结玩家，使任何输入键都无法移动头像。这对许多游戏机制都很有用。在执行一个不应因移动而被打断的重要动画时，或者在一个 [虚拟摄像机](/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/camera.md) 背对头像并且你不希望玩家盲目移动时，冻结玩家也是个好做法。

使用 `InputModifier` 组件在 `engine.PlayerEntity` 上使用，以防止玩家输入影响头像的移动。头像将保持静止，玩家只能旋转摄像机。

```ts
import {InputModifier, engine} from '@dcl/sdk/ecs'

InputModifier.create(engine.PlayerEntity, {
	mode: InputModifier.Mode.Standard({
		disableAll: true,
	}),
})
```

请记住以下注意事项：

* 当玩家的交互被禁用时，他们的头像仍然会受到外力影响，例如重力或移动平台。
* 该 `InputModifier` 组件只能与 `engine.PlayerEntity` 实体一起使用。它只能影响当前玩家，不能影响其他玩家。
* 该组件只会在头像处于你的场景边界内时影响玩家。一旦他们离开场景，其移动限制就会立即停止。
* 当玩家的交互被禁用时，玩家不能自由执行表情，但场景仍然可以在头像上触发动画。
* 玩家输入不会影响头像，但 [全局输入事件](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/system-based-events.md#global-input-events) 仍然可以被场景监听。你可以用它们来控制载具，或者使用一个 [虚拟摄像机](/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/camera.md) 来跟随另一个实体的移动，把它当作替代头像。

### 限制特定类型的移动

你不必完全冻结玩家，也可以限制玩家某些特定的移动方式。这可用于游戏性目的，例如通过禁止二段跳和滑翔来保持平台跳跃游戏的难度。这些能力甚至可以作为游戏机制动态切换，例如给玩家一个体力条，并在其耗尽时禁止他们奔跑。这也可用于设定场景氛围，例如在一个应当宁静的地点禁止奔跑或跳跃。 `InputModifier` 包括以下选项：

* `disableWalk`：玩家不能慢走（按住 control）。如果玩家尝试行走，在允许的情况下，他们会改为慢跑或奔跑。
* `disableRun`：玩家不能奔跑（按住 shift）。如果玩家尝试奔跑，在允许的情况下，他们会改为慢跑。
* `disableJog`：玩家不能慢跑（这是默认移动速度）。如果玩家尝试慢跑，在允许的情况下，他们会改为奔跑或行走。
* `disableJump`：玩家不能跳跃。
* `disableEmote`：玩家不能自主执行表情。场景仍可在玩家的头像上触发动画。
* `disableDoubleJump`：玩家不能进行二段跳。
* `disableGliding`：玩家不能滑翔。

```ts
import {InputModifier, engine} from '@dcl/sdk/ecs'

InputModifier.create(engine.PlayerEntity, {
	mode: InputModifier.Mode.Standard({
		disableAll: false,
		disableWalk: false,
		disableRun: true,
		disableJog: true,
		disableJump: true,
		disableEmote: true,
		disableDoubleJump: true,
		disableGliding: true
	}),
})
```

### 高级语法

要在不使用任何辅助函数的情况下使用该组件，你可以使用以下语法：

```ts
import {InputModifier, engine} from '@dcl/sdk/ecs'

InputModifier.createOrReplace(engine.PlayerEntity, {
	mode: {
		$case: 'standard',
		standard: {
			disableAll: false,
			disableWalk: false,
			disableRun: true,
			disableJog: true,
			disableJump: true,
			disableEmote: true,
		},
	},
})
```

## 移动设置

你可以影响玩家的移动方式，比如奔跑速度、跳跃高度等。这可以动态更改，例如允许玩家通过与物品交互来获得临时速度加成，或者在短时间内禁用玩家的跳跃能力。

为此，请添加一个 `AvatarLocomotionSettings` 组件到 `engine.PlayerEntity`.

```ts
import {AvatarLocomotionSettings, engine} from '@dcl/sdk/ecs'

AvatarLocomotionSettings.create(engine.PlayerEntity, {
	runSpeed: 10,
	jumpHeight: 2,
})
```

可用的属性如下：

* `walkSpeed`：玩家步行的速度，单位为米/秒。在桌面客户端中，玩家按住 control 键时会步行。
* `jogSpeed`：玩家慢跑的速度，单位为米/秒。这是玩家默认的移动方式。
* `runSpeed`：玩家奔跑的速度，单位为米/秒。在桌面客户端中，玩家按住 shift 键时会奔跑。
* `jumpHeight`：玩家跳跃的高度，单位为米。
* `runJumpHeight`：玩家奔跑后跳跃的高度，单位为米。
* `doubleJumpHeight`：二段跳时第二次跳跃的高度，单位为米。
* `glidingSpeed`：玩家滑翔时的水平移动速度，单位为米/秒。
* `glidingFallingSpeed`：玩家滑翔时的最大下落速度，单位为米/秒。这只会限制玩家的下降速度：向上的运动，例如场景持续力量带来的上升，不受限制。
* `hardLandingCooldown`：硬着陆后的冷却时间，单位为秒。这是玩家从高处坠落落地后，在能够再次移动前必须等待的时间。

作为参考，以下是这些属性的默认值：

* `walkSpeed`：1.5 米/秒
* `jogSpeed`：8 米/秒
* `runSpeed`：10 米/秒
* `glidingSpeed`：6 米/秒
* `glidingFallingSpeed`：1 米/秒
* `jumpHeight`：1 米
* `runJumpHeight`：1.5 米
* `doubleJumpHeight`：2 米
* `hardLandingCooldown`：0.75 秒

{% hint style="info" %}
**💡 提示**：在滑翔时，场景施加的持续力量会增强 1.5 倍，并且向上的力量可以抬升玩家。请参见 [滑翔时的力](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/player-physics.md#forces-while-gliding).
{% endhint %}

{% hint style="info" %}
**💡 提示**：这些属性都不能小于 0。如果你将其中一个设置为负值，它会被钳制为 0。将这些值设为 0 的效果与使用 `InputModifier` 来阻止使用某些按键的效果相同。

只有当玩家位于场景边界内时，你才能影响其移动。如果要影响其他玩家的头像，你必须在他们自己的实例中运行会影响其移动的代码。
{% endhint %}

你可以创建一个 [智能穿戴设备](/creator/content-creator-zh/chang-jing-sdk7/xiang-mu-lei-xing/smart-wearables.md) 可让玩家始终跑得更快或跳得更高。

为了确保在跑酷场景中没有人拥有不公平优势，你可以在场景中显式添加默认值来强制使用默认参数：

```ts
import {AvatarLocomotionSettings, engine} from '@dcl/sdk/ecs'

AvatarLocomotionSettings.create(engine.PlayerEntity, {
	runSpeed: 10,
	walkSpeed: 1.5,
	jogSpeed: 8 ,
	jumpHeight: 1,
	runJumpHeight: 1.5,
	hardLandingCooldown: 0.75
})
```

## 头像修改器区域

随着头像在 Decentraland 中穿行并经过各个场景，它们的行为和外观始终保持一致。不过，你可以添加一个 `AvatarModifierArea` 到你场景中的某个区域，以影响玩家头像进入该区域时的行为。

{% hint style="danger" %}
**❗警告**\
请将你在场景中使用的 `AvatarModifierAreas` 数量限制在很少几个以内。如果使用太多，可能会对性能产生显著影响。
{% endhint %}

### 放置头像修改器区域

添加一个带有 `AvatarModifierArea` 组件的实体，并使用一个 `Transform` 组件。

```ts
const entity = engine.addEntity()

AvatarModifierArea.create(entity, {
	area: Vector3.create(4, 3, 4),
	modifiers: [AvatarModifierType.AMT_HIDE_AVATARS],
	excludeIds: []
})

Transform.create(entity, {
	position: Vector3.create(8, 0, 8),
})
```

在创建一个 `AvatarModifierArea` 组件时，你必须提供以下内容：

* `area`：修改器区域的大小
* `modifiers`：一个数组，列出要在该区域中实现的修改器。此属性使用 `AvatarModifierType` 枚举中的值。

支持的修改器有：

* `AvatarModifierType.AMT_HIDE_AVATARS`
* `AvatarModifierType.AMT_DISABLE_PASSPORTS`
* `AvatarModifierType.AMT_HIDE_NAMETAGS`

一个 AvatarModifierArea 的所有效果 `AvatarModifierArea` 仅会在其区域内生效。玩家走出该区域后会恢复正常。

一个 `AvatarModifierArea` 只会影响处于该区域内的玩家。进入该区域不会影响该区域外其他玩家的感知方式。

一个 AvatarModifierArea 的效果会在每个玩家本地进行计算。你可以有一个 `AvatarModifierArea` 仅存在于某些玩家的场景中，而对其他玩家不存在。例如，你可以制作一个“marco polo”游戏，在该游戏中，场景里只有一名玩家拥有一个会隐藏所有其他玩家的修改器区域。其他玩家在其本地版本的场景中没有这个修改器区域，因此能够正常互相看到。 `AvatarModifierArea` 如果某个区域隐藏了头像，那么那些在其本地版本场景中没有该区域的玩家会正常看到所有头像，甚至包括那些自己感知为已隐藏的头像。拥有该区域的玩家在进入它时，会感知到自己和所有其他头像都受该区域影响。

如果该区域隐藏了头像，那么那些在其本地版本的场景中没有该区域的玩家会正常看到所有头像，甚至包括那些自己感知为已隐藏的头像。拥有该区域的玩家在进入它时，会感知到自己和所有其他头像都受该区域影响。

{% hint style="warning" %}
**📔 注意**：头像修改器区域会受到 *位置* 和 *旋转* 其宿主实体的 Transform 组件的 *缩放*.
{% endhint %}

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

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

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

### 隐藏头像

当玩家走入一个 `AvatarModifierArea` 拥有 `AvatarModifierType.AMT_HIDE_AVATARS` 修改器时，玩家的头像将不再被渲染。这既适用于第三人称视角下的玩家，也适用于其他玩家走入该区域时。

```ts
const entity = engine.addEntity()

AvatarModifierArea.create(entity, {
	area: Vector3.create(4, 3, 4),
	modifiers: [AvatarModifierType.AMT_HIDE_AVATARS],
	excludeIds: []
})

Transform.create(entity, {
	position: Vector3.create(8, 0, 8),
})
```

这使你可以用任何你想在场景中展示的自定义头像来替换默认的 Decentraland 头像。请注意，如果你想看到其他玩家使用自定义头像，你应该自己处理玩家位置的同步。

### 禁用护照弹窗

当玩家走入一个 `AvatarModifierArea` 拥有 `AvatarModifierType.AMT_DISABLE_PASSPORTS` 修改器后，点击他们将不再打开显示玩家简介、物品栏等内容的护照 UI。

```ts
const entity = engine.addEntity()

AvatarModifierArea.create(entity, {
	area: Vector3.create(4, 3, 4),
	modifiers: [AvatarModifierType.AMT_DISABLE_PASSPORTS],
	excludeIds: []
})

Transform.create(entity, {
	position: Vector3.create(8, 0, 8),
})
```

这在游戏中特别有用，因为意外打开此 UI 可能会打断游戏流程，例如在多人射击游戏中。

### 隐藏名字标签

当玩家走入一个 `AvatarModifierArea` 拥有 `AvatarModifierType.AMT_HIDE_NAMETAGS` 修改器后，玩家的名字标签会被隐藏，而头像本身仍然可见。

```ts
const entity = engine.addEntity()

AvatarModifierArea.create(entity, {
	area: Vector3.create(4, 3, 4),
	modifiers: [AvatarModifierType.AMT_HIDE_NAMETAGS],
	excludeIds: []
})

Transform.create(entity, {
	position: Vector3.create(8, 0, 8),
})
```

这适用于舞台、演示或脚本场景，在这些场景中你想隐藏玩家名字标签而不隐藏头像本身。例如，在表演期间你可能希望获得更干净的视觉体验，让头像可见，但悬浮的名字不会分散观众注意力。

{% hint style="info" %}
**💡 提示**: `AMT_HIDE_AVATARS` 已经会连同头像一起隐藏名字标签，因此你无需在使用 `AMT_HIDE_NAMETAGS` 时再添加 `AMT_HIDE_AVATARS`。使用 `AMT_HIDE_NAMETAGS` 仅当你想在保持头像可见的同时隐藏名字标签时。
{% endhint %}

你可以将 `AMT_HIDE_NAMETAGS` 与其他修改器结合使用，例如 `AMT_DISABLE_PASSPORTS` ，在同一个区域中：

```ts
const entity = engine.addEntity()

AvatarModifierArea.create(entity, {
	area: Vector3.create(4, 3, 4),
	modifiers: [AvatarModifierType.AMT_HIDE_NAMETAGS, AvatarModifierType.AMT_DISABLE_PASSPORTS],
	excludeIds: []
})

Transform.create(entity, {
	position: Vector3.create(8, 0, 8),
})
```

{% hint style="info" %}
**💡 提示**：名字标签只会在玩家的头部或躯干位于该区域内时被隐藏。如果该区域太矮，而玩家通过二段跳跳到其上方，名字标签就会短暂重新出现。请将该区域设置得足够高，以覆盖预期的移动范围。
{% endhint %}

### 排除头像

你可以通过将玩家 Id 添加到修改器区域的 `excludeIds` 属性中的数组，来排除某些玩家不受修改器区域影响。

此示例会隐藏某个区域中的所有头像，但拥有特定 ID 的玩家除外。比如你可以在现场活动中这样使用，只显示舞台上的活动主持人，并隐藏任何跳上舞台的其他玩家。

```ts
const entity = engine.addEntity()

AvatarModifierArea.create(entity, {
	area: Vector3.create(4, 3, 4),
	modifiers: [AvatarModifierType.AMT_HIDE_AVATARS],
	excludeIds: ['0xx1...', '0xx2...'],
})

Transform.create(entity, {
	position: Vector3.create(8, 0, 8),
})
```

{% hint style="warning" %}
**📔 注意**：请确保玩家 ID 全都使用小写字母。必要时使用 `.toLowerCase()` 。
{% endhint %}

修改器区域会在每个玩家的实例中本地运行。被排除的 ID 列表可以因玩家而异。下面的示例中，每个玩家都会把自己的 ID 从隐藏头像的修改器中排除，这样他们各自都只能看到自己的头像，而看不到其他人的头像。

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

export function main() {
	let userData = getPlayer()
	if (!userData) return

	const entity = engine.addEntity()

	AvatarModifierArea.create(entity, {
		area: Vector3.create(16, 5, 16),
		modifiers: [AvatarModifierType.AMT_HIDE_AVATARS],
		excludeIds: [userData.userId],
	})

	Transform.create(entity, {
		position: Vector3.create(8, 0, 8),
	})
}
```

{% hint style="danger" %}
**❗警告**\
如果排除 ID 列表将会定期更改（例如根据玩家进入或离开某个区域），请确保列表保持有序。对数组执行 `.sort()` ，这样每次传递时列表都会保持相同顺序。这样一来，系统只会计算列表中的变化。否则，这可能会对场景性能产生显著影响。

```ts
AvatarModifierArea.create(entity, {
	area: Vector3.create(16, 5, 16),
	modifiers: [AvatarModifierType.AMT_HIDE_AVATARS],
	excludeIds: myAvatarList.sort(),
})
```

{% endhint %}

### 调试修改器区域

仅根据代码很难确切知道修改器区域覆盖了场景中的哪些部分。可视化反馈对确认它们放置得是否合适很有帮助。

要验证一个 `AvatarModifierArea` 或一个 `CameraModeArea`，请给持有它的实体添加一个 `MeshRenderer` 带有一个 `盒子` 形状的 `area` ，并将缩放设置为与修改器区域的

{% hint style="warning" %}
**📔 注意**：修改器区域不受 `缩放` transform 的属性影响，它们的大小基于其 `area` 属性。
{% endhint %}

```ts
const entity = engine.addEntity()
const areaSize = Vector3.create(8, 3, 8)

AvatarModifierArea.create(entity, {
	area: areaSize,
	modifiers: [AvatarModifierType.AMT_HIDE_AVATARS],
  	excludeIds: []
})

Transform.create(entity, {
	position: Vector3.create(8, 0, 8),
	scale: areaSize,
})

MeshRenderer.setBox(entity)
Material.setPbrMaterial(entity, {
	albedoColor: Color4.create(0.5, 0.5, 0.5, 0.5),
})
```

要激活修改器区域的效果，玩家的头部或躯干必须进入该区域。只有玩家的脚在区域内时不会生效。确保玩家不能通过跳跃轻易避开该区域。

{% hint style="warning" %}
**📔 注意**：整个区域应完全位于你场景的边界内。
{% endhint %}

## 更改头像外观

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

参见 [NPC 头像](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/npc-avatars.md) 了解更多详情。

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

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

{% hint style="info" %}
**💡 提示**：有关这些 API 的可运行示例，请查看 [`0,1-input-modifier`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/0,1-input-modifier) 测试场景，它会分别切换每个 `InputModifier` 移动标志，并展示在移动被阻止时，头像仍被移动平台承载； [`9,99-modifier-areas`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/9,99-modifier-areas)，它结合了 `AvatarModifierArea` 与运行时修改的 `excludeIds`； [`10,99-avatar-modifier-hide-nametags`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/10,99-avatar-modifier-hide-nametags)，它隔离了 `AMT_HIDE_NAMETAGS` 修改器。
{% 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 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.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/player-avatar.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.
