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

# 플레이어 아바타

플레이어의 아바타를 제어하는 방법을 알아보세요

플레이어의 아바타를 제어하고 플레이어에게 제공되는 게임플레이 경험을 바꿀 수 있는 여러 방법이 있습니다.

플레이어가 아닌 아바타를 다루는 방법은 다음을 참조하세요: [NPC 아바타](/creator/content-creator-ko/sdk7/interactivity/npc-avatars.md).

## 플레이어 이동

{% hint style="info" %}
**💡 팁**: 플레이어를 이동시키는 가장 쉬운 방법은 [Creator Hub의 씬 편집기](/creator/content-creator-ko/scene-editor/get-started/about-editor.md)를 사용하는 것입니다. 코드 없이 사용할 수 있는 **플레이어 이동** 또는 **플레이어를 여기로 이동** Actions를 참조하세요. 자세한 내용은 [어떤 항목이든 스마트 아이템으로 만들기](/creator/content-creator-ko/scene-editor/interactivity/make-any-item-smart.md).
{% endhint %}

씬에서 플레이어의 위치를 바꾸려면 `movePlayerTo()` 함수를 사용하세요. 이 함수는 다음 세 가지 속성을 가진 객체를 인수로 받습니다:

* `newRelativePosition`: 플레이어를 배치할 위치로, Vector3로 표현됩니다.
* `cameraTarget`: (선택 사항) 카메라가 바라볼 방향으로, 바라볼 공간의 한 점의 좌표를 나타내는 Vector3로 표현됩니다. 값이 제공되지 않으면 이동 전과 같은 회전을 유지합니다.
* `avatarTarget`: (선택 사항) 아바타가 바라볼 방향으로, 바라볼 공간의 한 점의 좌표를 나타내는 Vector3로 표현됩니다. 값이 제공되지 않으면 이동 전과 같은 회전을 유지합니다. 플레이어가 1인칭 카메라 모드에 있으면 카메라와 아바타의 회전은 같습니다.
* `지속 시간`: (선택 사항) 전환에 걸릴 시간(초)입니다. 값이 제공되지 않으면 전환은 즉시 일어납니다. 지속 시간이 제공되면 아바타는 이 새 위치로 걸어가거나 달려갑니다.

{% 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: '클릭' },
	},
	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-ko/sdk7/interactivity/external-links.md#teleports).
{% endhint %}

그 `movePlayerTo()` 함수는 await 가능하므로, 이동에 시간이 걸리는 경우 `await` 를 사용해 플레이어가 목적지에 도달할 때까지 기다릴 수 있습니다.

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

pointerEventsSystem.onPointerDown(
	{
		entity: myEntity,
		opts: { button: InputAction.IA_POINTER, hoverText: '클릭' },
	},
	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` 함수는 결코 resolve되지 않습니다. 전환이 진행되는 동안 `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: '클릭' },
	},
	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 %}

## 애니메이션 재생

씬 코드의 일부로 플레이어가 애니메이션을 수행하게 할 수 있습니다. 이는 몰입감을 높이는 데 도움이 되며, 다른 플레이어들이 서로 무엇을 하는지 전달하는 데도 도움이 될 수 있습니다. 아바타 애니메이션은 플레이어(3인칭 시점)와 주변의 다른 모든 플레이어에게 보입니다.

플레이어가 제어하는 전신 애니메이션은 걷기나 점프와 같은 기본 이동 애니메이션에 의해 덮어써집니다. 따라서 씬에서 재생되는 전신 애니메이션은 플레이어가 가만히 서 있을 때만 재생됩니다. 플레이어가 걷거나 점프하면 모든 전신 애니메이션은 중단됩니다. 상체 애니메이션은 이동에 의해 중단되지 않습니다.

{% hint style="warning" %}
**📔 참고**: 플레이어는 이미 씬 경계 안에 서 있는 경우에만 애니메이션을 적용할 수 있으며, 인접한 씬에 있을 때는 할 수 없습니다. 스마트 웨어러블은 어디서나 애니메이션을 재생할 수 있습니다.

플레이어가 애니메이션을 수행하는 동안에는 충돌의 영향을 받지 않으며, 움직임도 씬의 물리 법칙에 의해 제한되지 않습니다. 또한 애니메이션이 플레이어를 원래 위치에서 이동시키는 경우(예를 들어 애니메이션에 점프가 포함되는 경우)에도 플레이어의 Transform 컴포넌트는 이 이동의 영향을 받지 않습니다.
{% endhint %}

### 씬 편집기 사용

플레이어가 애니메이션을 수행하게 만드는 가장 쉬운 방법은 씬 편집기를 사용하는 것입니다. 코드 없이 **이모트 재생** 액션을 사용하여 기본 애니메이션을 재생하거나 **커스텀 이모트 재생** 액션을 사용하여 파일에서 애니메이션을 재생하세요. 자세한 내용은 [어떤 항목이든 스마트 아이템으로 만들기](/creator/content-creator-ko/scene-editor/interactivity/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: '댄스' },
	},
	() => {
		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: '눈덩이 만들기' },
	},
	() => {
		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: '환호' },
	},
	() => {
		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-ko/sdk7/3d/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-ko/sdk7/interactivity/button-events/system-based-events.md#global-input-events) 는 여전히 씬에서 수신할 수 있습니다. 이를 차량 제어에 사용하거나, 또는 [가상 카메라로 전환합니다.](/creator/content-creator-ko/sdk7/3d/camera.md) 를 사용해 다른 엔티티가 이동하는 것을 따라가며 이를 대체 아바타처럼 취급할 수 있습니다.

### 특정 이동 방식 제한

플레이어를 완전히 고정하는 대신, 플레이어의 특정 이동 방식만 제한할 수 있습니다. 이는 게임플레이상의 이유로 사용할 수 있는데, 예를 들어 더블 점프와 글라이드를 막아 플랫폼 게임의 난이도를 유지하는 데 도움이 됩니다. 이러한 능력은 게임 메커니즘으로 동적으로 켜고 끌 수도 있습니다. 예를 들어 플레이어에게 스태미나 바를 주고 그것이 바닥났을 때 달리지 못하게 할 수 있습니다. 또한 씬의 분위기를 정하는 데에도 사용할 수 있습니다. 예를 들어 평온한 장소에서 달리기나 점프를 금지하는 식입니다.  `InputModifier` 에는 다음 옵션이 포함됩니다:

* `disableWalk`: 플레이어는 천천히 걸을 수 없습니다(컨트롤 키 누르기). 플레이어가 걷기를 시도하면, 허용되는 경우 대신 조깅하거나 달리게 됩니다.
* `disableRun`: 플레이어는 달릴 수 없습니다(쉬프트 키 누르기). 플레이어가 달리기를 시도하면, 허용되는 경우 대신 조깅하게 됩니다.
* `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`: 플레이어가 걷는 속도(미터/초)입니다. 데스크톱 클라이언트에서는 컨트롤 키를 눌러 걷습니다.
* `jogSpeed`: 플레이어가 조깅하는 속도(미터/초)입니다. 이것이 플레이어의 기본 이동 방식입니다.
* `runSpeed`: 플레이어가 달리는 속도(미터/초)입니다. 데스크톱 클라이언트에서는 쉬프트 키를 눌러 달립니다.
* `jumpHeight`: 플레이어가 점프하는 높이(미터)입니다.
* `runJumpHeight`: 플레이어가 달린 후 점프하는 높이(미터)입니다.
* `doubleJumpHeight`: 더블 점프 시 두 번째 점프의 높이(미터)입니다.
* `glidingSpeed`: 플레이어가 글라이딩하는 동안 움직이는 수평 속도(미터/초)입니다.
* `glidingFallingSpeed`: 플레이어가 글라이딩하는 동안의 최대 낙하 속도(미터/초)입니다. 이는 하강만 제한하며, 씬의 지속 힘으로부터의 들어올림 같은 상향 운동은 제한하지 않습니다.
* `hardLandingCooldown`: 강한 착지 후 쿨다운(초)입니다. 높은 곳에서 떨어진 뒤 다시 움직일 수 있기 전에 플레이어가 기다려야 하는 시간입니다.

참고용으로, 해당 속성의 기본값은 다음과 같습니다:

* `walkSpeed`: 1.5m/s
* `jogSpeed`: 8m/s
* `runSpeed`: 10m/s
* `glidingSpeed`: 6m/s
* `glidingFallingSpeed`: 1m/s
* `jumpHeight`: 1m
* `runJumpHeight`: 1.5m
* `doubleJumpHeight`: 2m
* `hardLandingCooldown`: 0.75초

{% hint style="info" %}
**💡 팁**: 글라이딩하는 동안 씬에서 적용되는 지속 힘은 1.5배 더 강해지며, 위쪽 힘도 플레이어를 들어올릴 수 있습니다. 자세한 내용은 [글라이딩 중의 힘](/creator/content-creator-ko/sdk7/interactivity/player-physics.md#forces-while-gliding).
{% endhint %}

{% hint style="info" %}
**💡 팁**: 이 속성들 중 어느 것도 0보다 낮을 수 없습니다. 그중 하나를 음수로 설정하면 0으로 제한됩니다. 이 값들을 0으로 설정하면 `InputModifier` 를 사용해 특정 키 사용을 차단하는 것과 같은 효과가 있습니다.

플레이어가 씬 경계 안에 있을 때만 플레이어의 이동에 영향을 줄 수 있습니다. 다른 플레이어의 아바타에 영향을 주려면, 해당 아바타의 이동에 영향을 주는 코드를 그들 자신의 인스턴스에서 실행해야 합니다.
{% endhint %}

다음을 만들 수 있습니다: [스마트 웨어러블](/creator/content-creator-ko/sdk7/kinds-of-projects/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` 일부 플레이어에게만 씬에 존재하고 다른 플레이어에게는 존재하지 않는 것입니다. 예를 들어 "마르코 폴로" 게임을 만들 수 있는데, 씬의 한 플레이어에게만 다른 모든 플레이어를 숨기는 수정 영역이 있습니다. 자신의 로컬 버전 씬에 이 수정 영역이 없는 다른 모든 플레이어들은 서로를 정상적으로 볼 수 있습니다.

영역이 아바타를 숨기면, 자신의 로컬 버전 씬에 해당 영역이 없는 플레이어는 자신이 숨겨져 있다고 느끼는 경우를 포함해 모든 아바타를 정상적으로 볼 수 있습니다. 해당 영역이 있는 플레이어는 그 영역에 들어갈 때 자신과 다른 모든 아바타가 그 영역의 영향을 받는 것으로 경험하게 됩니다.

{% hint style="warning" %}
**📔 참고**: 아바타 수정 영역은 다음의 영향을 받습니다: *위치* 및 *회전* 호스트 엔티티의 Transform 컴포넌트의, 하지만 다음의 영향을 받지는 않습니다: *크기*.
{% endhint %}

{% hint style="warning" %}
**📔 참고**:  `AvatarModifierArea`컴포넌트는 다음을 통해 가져와야 합니다:

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

참고 [가져오기](/creator/content-creator-ko/sdk7/getting-started/coding-scenes.md#imports) 를 사용하면 이를 쉽게 처리할 수 있습니다.
{% endhint %}

### 아바타 숨기기

플레이어가 다음에 들어가면 `AvatarModifierArea` 다음이 있는 `AvatarModifierType.AMT_HIDE_AVATARS` 수정자를, 플레이어의 아바타 렌더링이 중지됩니다. 이는 3인칭 시점의 플레이어에게도, 다른 플레이어가 영역에 들어올 때에도 적용됩니다.

```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-ko/sdk7/interactivity/npc-avatars.md) 자세한 내용은 다음을 참조하세요.

{% hint style="warning" %}
**📔 참고**: 플레이어가 해당 아바타를 완전히 제어할 수 있게 하려면, 버튼 이벤트를 수신해 버튼을 눌렀는지 감지한 다음 NPC 아바타에서 해당 애니메이션을 트리거해야 합니다. 다음을 참고하세요: [버튼 이벤트](/creator/content-creator-ko/sdk7/interactivity/button-events/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-ko/sdk7/interactivity/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.
