> 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/3d/entity-positioning.md).

# 엔티티 위치 설정

씬에서 엔티티의 위치, 회전, 크기를 설정하는 방법

다음을 설정하여 *위치*, *회전* 과 *크기* 임의의 엔티티에 대해 다음을 사용하여 `Transform` 컴포넌트. 이는 3D 공간의 어떤 엔티티에든 사용할 수 있으며, 엔티티가 렌더링되는 위치에 영향을 줍니다. 여기에는 기본 도형(큐브, 구, 평면 등), 3D 텍스트 도형, NFT 도형, 그리고 3D 모델(`GltfContainer`).

## Creator Hub의 Scene Editor를 사용하세요

Scene Editor를 통해 씬에 항목을 추가하면, 그것은 암묵적으로 **Transform** 컴포넌트를 포함합니다. 그런 다음 엔티티의 위치, 회전 또는 크기를 변경하여 엔티티의 Transform 컴포넌트 값이 암묵적으로 바뀝니다. 더 높은 정밀도를 위해 Scene Editor의 UI에서 수치를 직접 입력할 수도 있습니다.

## 코드 핵심

![](https://3980763956-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-417a02dcf0fd40f5032551a0c6996becac7e7166%2Fecs-simple-components-new.png?alt=media\&token=181a73c9-363a-4328-9874-6fed49447dc3)

```ts
// 새 엔티티 생성
const ball = engine.addEntity()

// 이 엔티티에 모양을 부여하여 보이게 함
MeshRenderer.setSphere(ball)

// 이 엔티티에 Transform 컴포넌트 부여
Transform.create(ball, {
	position: Vector3.create(5, 1, 5),
	scale: Vector3.create(1, 1, 1),
	rotation: Quaternion.Identity(),
})
```

시간에 걸쳐 씬 안의 엔티티를 이동, 회전 또는 크기 조정하려면 이 컴포넌트의 값을 프레임마다 조금씩 변경하세요. 자세한 내용과 모범 사례는 [엔티티 이동](/creator/content-creator-ko/sdk7/3d/move-entities.md) 를 참조하세요.

{% hint style="warning" %}
**📔 참고**: `Vector3` 과 `Quaternion` 는 다음과 같이 가져와야 합니다.

> `import { Vector3, Quaternion } from "@dcl/sdk/math"`

다음 [가져오기](/creator/content-creator-ko/sdk7/getting-started/coding-scenes.md#imports) 를 참고해 쉽게 처리하는 방법을 확인하세요.
{% endhint %}

## 위치

`위치` 는 *3D 벡터*이며, 엔티티 중심의 위치를 세 축 모두에 대해 설정합니다. *x*, *y*, 그리고 *z*. 참고: [도형 유형](/creator/content-creator-ko/sdk7/3d/special-types.md) 자세한 내용은.

```ts
// 새 엔티티 생성
const ball = engine.addEntity()

// 미리 정의된 위치로 Transform 생성
Transform.create(ball, {
	  position: Vector3.create(5, 1, 5)
})

// 변경 가능한 Transform 버전 가져오기
const mutableTransform = Transform.getMutable(ball)

// 객체로 위치 설정
mutableTransform.position = { x: 5, y: 1, z: 5 }

// 객체로 위치 설정(대체 문법)
mutableTransform.position = Vector3.create(2, 1, 4)

// 각 축을 개별적으로 설정
mutableTransform.position.x = 3
mutableTransform.position.y = 1
mutableTransform.position.z = 3
```

위치를 설정할 때 다음 사항을 염두에 두세요:

* 위치 벡터의 숫자는 *미터* (엔티티가 크기가 조정된 엔티티의 자식이 아닌 경우).
* 단일 parcel로 이루어진 씬의 크기는 16m x 16m입니다. 씬의 중심(지면 높이 기준)은 `x:8, y:0, z:8`입니다. 씬이 여러 parcel로 이루어져 있다면 중심은 그 배치에 따라 달라집니다.
* `x:0, y:0, z:0` 는 *남서쪽* 을 가리키며, 씬의 기준 parcel의 지면 높이 기준 모서리를 뜻합니다.

  > 팁: 씬 미리보기를 볼 때, 씬의 (0,0,0) 지점에 나침반이 표시되며 각 축의 라벨이 기준으로 나타납니다.

  > 참고: 씬의 기준 parcel은 `base` 속성을 편집하여 변경할 수 있습니다. *scene.json*.
* 방향을 더 잘 파악하려면 자신의 *왼쪽* 손을 사용하세요:
  * 검지(앞을 가리킴)는 *z* 축입니다.
  * 중지(옆을 가리킴)는 *x* 축입니다.
  * 엄지(위쪽을 가리킴)는 *y* 축입니다.
* 엔티티가 다른 엔티티의 자식이라면, `x:0, y:0, z:0` 는 씬의 어디에 있든 부모 엔티티의 중심을 가리킵니다.
* 씬의 모든 엔티티는 항상 자신이 차지하는 parcel의 경계 안에 있어야 합니다. 엔티티가 이 경계를 벗어나면 오류가 발생합니다.

  > 팁: 씬을 미리보기 모드로 볼 때, 경계를 벗어난 엔티티는 *빨강*.
* 씬의 높이에도 제한이 있습니다. 차지하는 parcel 수와 상관없이 모든 씬의 최대 높이는 330미터입니다. 200미터보다 높은 곳에 배치된 엔티티는 멀티플레이어 동기화 문제가 발생할 수 있습니다. 자세한 내용은 [씬 제한 사항](/creator/content-creator-ko/sdk7/optimizing/scene-limitations.md) 자세한 내용은.

## 회전

`회전` 은 [*사원수*](https://en.wikipedia.org/wiki/Quaternion)인 네 개의 숫자로 이루어진 시스템인 *x*, *y*, *z* 과 *w*로 저장됩니다. 이 숫자들은 각각 -1에서 1까지의 값을 가집니다. 자세한 내용은 [도형 유형](/creator/content-creator-ko/sdk7/3d/special-types.md) 자세한 내용은.

```ts
// 새 엔티티 생성
const cube = engine.addEntity()

// 미리 정의된 회전값 0으로 Transform 생성
Transform.create(cube, {
	  rotation: Quaternion.Identity()
})

// 변경 가능한 Transform 버전 가져오기
const mutableTransform = Transform.getMutable(cube)

// 오일러 각을 사용해 객체로 회전 설정
mutableTransform.rotation = Quaternion.fromEulerDegrees(0, 90, 0)

// 객체로 회전 설정
mutableTransform.rotation = { x: 0.1, y: 0.5, z: 0.5, w: 0 }

// 각 축을 개별적으로 설정
mutableTransform.rotation.x = 0
mutableTransform.rotation.y = 1
mutableTransform.rotation.z = 0.3
mutableTransform.rotation.w = 0
```

회전 필드를 다음 방식으로도 설정할 수 있습니다. [*오일러* 각](https://en.wikipedia.org/wiki/Euler_angles), 즉 더 흔히 쓰이며 대부분의 사람들이 익숙한 0부터 360까지의 숫자를 사용하는 *x*, *y* 과 *z* 표기법입니다. 오일러 각을 사용하려면 다음 표기법 중 하나를 사용하세요:

```ts
// 오일러 각으로 미리 정의된 회전을 사용해 Transform 생성
Transform.create(cube, {
	  rotation: Quaternion.fromEulerDegrees(0, 90, 0)
})

// 변경 가능한 Transform 버전 가져오기
const mutableTransform = Transform.getMutable(cube)

// 오일러 각을 사용해 객체로 회전 설정
mutableTransform.rotation = Quaternion.fromEulerDegrees(0, 90, 0)
```

다음과 같은 *3D 벡터* 를 사용하여 오일러 각을 나타낼 때, *x*, *y* 과 *z* 해당 축의 회전을 각도로 표현합니다. 한 바퀴는 360도가 필요합니다.

엔티티의 회전을 가져오면 기본적으로 쿼터니언이 반환됩니다. 오일러 각으로 표현된 회전을 얻으려면 `Quaternion.toEulerAngles()`:

```ts
// 읽기 전용 Transform 버전 가져오기
const transform = Transform.get(cube)

// 오일러 각으로 표현된 회전 얻기
const eulerAngle = Quaternion.toEulerAngles(transform.rotation)
```

## 엔티티의 전역 위치와 회전 가져오기

이 `getWorldPosition` 과 `getWorldRotation` 함수는 엔티티의 전역 위치와 회전을 반환합니다. 즉, 부모 계층 구조를 무시하고 플레이어가 보게 될 항목의 인식된 위치 또는 회전을 반환합니다.

* `getWorldPosition(engine, entity: Entity): Vector3Type`: 이 함수는 엔티티의 월드 위치를 반환합니다. 엔티티 자체에 부모 엔티티가 있다면 모든 부모 엔티티의 위치를 고려하여 반환하며, `{x: 0, y: 0, z: 0}` 를 반환합니다.

```ts
const worldPos = getWorldPosition(engine, childEntity)
console.log(`월드 위치: ${worldPos.x}, ${worldPos.y}, ${worldPos.z}`)
```

* `getWorldRotation(engine, entity: Entity): QuaternionType`: 이 함수는 엔티티의 월드 회전을 반환합니다. 엔티티 자체에 부모 엔티티가 있다면 모든 부모 엔티티의 회전을 고려합니다. 이는 `Quaternion` 타입을 반환하며, 항등 쿼터니언인 `{x: 0, y: 0, z: 0, w: 1}` 를 반환합니다.

```ts
const worldRot = getWorldRotation(engine, childEntity)
console.log(`월드 회전: ${worldRot.x}, ${worldRot.y}, ${worldRot.z}, ${worldRot.w}`)
```

{% hint style="info" %}
**참고:** 전역 위치와 전역 회전은 Genesis City가 아니라 씬 내부의 좌표를 기준으로 합니다.
{% endhint %}

## 플레이어를 향하게 하기

다음을 *빌보드* 컴포넌트를 엔티티에 추가하여 항상 플레이어를 향하도록 회전하게 합니다.

빌보드는 90년대 3D 게임에서 흔히 사용되던 기법으로, 대부분의 엔티티가 항상 플레이어를 향하는 2D 평면이었습니다. 같은 아이디어는 3D 모델을 회전시키는 데도 사용할 수 있습니다.

```ts
// 새 엔티티 생성
const cube = engine.addEntity()

// 엔티티에 보이는 모양 부여
MeshRenderer.setBox(cube)

// 미리 정의된 위치로 Transform 생성
Transform.create(cube, {
	  position: Vector3.create(5, 1, 5)
})

// 엔티티에 Billboard 컴포넌트 부여
Billboard.create(cube, {})
```

다음 매개변수로 빌보드의 동작을 설정할 수 있습니다:

* `billboardMode`: `BillboardMode` 값을 사용하여 어떤 회전 축이 자동으로 플레이어를 향할지 설정합니다:
  * `BillboardMode.BM_ALL`: 엔티티가 모든 회전 축에서 플레이어를 향하도록 회전합니다. 플레이어가 엔티티보다 훨씬 위에 있으면, 엔티티는 위를 향하게 됩니다.
  * `BillboardMode.BM_NONE`: 엔티티는 전혀 회전하지 않습니다.
  * `BillboardMode.BM_X`: 엔티티는 자신의 *x* 회전 축에서만 회전합니다.
  * `BillboardMode.BM_Y`: 엔티티는 자신의 *y* 회전 축. 좌우로만 회전하며, 위아래로는 회전하지 않습니다. 플레이어가 엔티티 위나 아래에 있으면 지면에 수직인 상태를 유지합니다.
  * `BillboardMode.BM_Z`: 엔티티는 자신의 *z* 회전 축에서만 회전합니다.
* `targetEntity`: (선택 사항) 플레이어의 카메라 대신 빌보드가 향하도록 회전할 엔티티입니다. 참조된 엔티티가 존재하지 않으면(예: 아직 생성되지 않았거나 제거된 경우) 빌보드는 회전을 멈추고 해당 엔티티가 다시 존재할 때까지 마지막 방향을 유지합니다. 이를 `engine.CameraEntity` 로 설정하는 것은 비워 두는 것과 같습니다.

```ts
// 평평한 빌보드
const perpendicularPlane = engine.addEntity()

Transform.create(perpendicularPlane, {
	position: Vector3.create(8, 1, 8),
})

MeshRenderer.setPlane(perpendicularPlane)

Billboard.create(perpendicularPlane, {
	billboardMode: BillboardMode.BM_Y,
})

// 텍스트 라벨
const textLabel = engine.addEntity()

Transform.create(textLabel, {
	position: Vector3.create(6, 1, 6),
})

TextShape.create(textLabel, {
	text: '이 텍스트는 항상 읽을 수 있습니다',
})

Billboard.create(textLabel)

// 플레이어 대신 다른 엔티티를 향하는 표지판
const sphere = engine.addEntity()

Transform.create(sphere, {
	position: Vector3.create(4, 2, 4),
})

MeshRenderer.setSphere(sphere)

const sign = engine.addEntity()

Transform.create(sign, {
	position: Vector3.create(8, 1, 8),
})

TextShape.create(sign, {
	text: '구체를 보고 있음',
})

Billboard.create(sign, {
	targetEntity: sphere,
})
```

{% hint style="info" %}
**💡 팁**: 빌보드는 *텍스트* 엔티티에 추가하기에 매우 유용합니다. 항상 읽기 쉽도록 만들어 주기 때문입니다.
{% endhint %}

이 `회전` 엔티티의 `Transform` 컴포넌트 값은 빌보드가 플레이어를 따라다녀도 바뀌지 않습니다.

엔티티에 `빌보드` 컴포넌트와 `Transform` 컴포넌트를 `회전` 값이 모두 있다면, 플레이어는 해당 엔티티가 빌보드처럼 회전하는 것을 보게 됩니다. 빌보드가 모든 축에 영향을 주지 않는 경우, 나머지 축은 `Transform` 컴포넌트를 추가해야 합니다.

{% hint style="warning" %}
**📔 참고**: 동시에 여러 플레이어가 있는 경우, 각 플레이어는 자신을 향하는 빌보드 모드의 엔티티를 보게 됩니다. 빌보드 회전은 각 플레이어마다 로컬로 계산되며, 다른 플레이어가 보는 것에는 영향을 주지 않습니다. 이 규칙은 `targetEntity`:가 있는 빌보드에는 적용되지 않습니다. 대상의 위치가 씬의 일부이기 때문에 모든 플레이어는 그 빌보드가 같은 방향을 향하는 것을 보게 됩니다.
{% endhint %}

## 좌표 세트를 향하기

엔티티 A가 엔티티 B를 바라보게 하려면:

```
1) 엔티티 B의 위치에서 엔티티 A의 위치를 빼서, 두 엔티티 사이의 거리를 나타내는 벡터를 구합니다.
2) 그 벡터를 정규화하여 길이가 1이 되도록 하되, 방향은 유지합니다.
3) `Quaternion.lookRotation`을 사용하여 그 방향으로 회전하는 것을 나타내는 Quaternion 회전을 얻습니다.
4) 그 Quaternion을 엔티티 A의 회전으로 설정합니다.
```

```ts
export function turn(entity: Entity, target: Vector3.ReadonlyVector3) {
	const transform = Transform.getMutable(entity)
	const difference = Vector3.subtract(target, transform.position)
	const normalizedDifference = Vector3.normalize(difference)
	transform.rotation = Quaternion.lookRotation(normalizedDifference)
}
```

## 스케일

`크기` 역시 *3D 벡터*, `Vector3` 객체로 저장되며, *x*, *y* 과 *z* 축의 스케일 계수를 포함합니다. 엔티티의 모양은 기본 도형이든 3D 모델이든 이에 맞게 조정됩니다.

기본 스케일은 1이므로, 1보다 큰 값을 넣으면 엔티티가 늘어나고 1보다 작은 값을 넣으면 줄어듭니다.

```ts
// 새 엔티티 생성
const ball = engine.addEntity()

// 미리 정의된 위치로 Transform 생성
Transform.create(ball, {
	  scale: Vector3.create(5, 5, 5)
})

// 변경 가능한 Transform 버전 가져오기
const mutableTransform = Transform.getMutable(ball)

// Vector3로 스케일 설정

mutableTransform.scale = Vector3.create(2, 2, 2)

// 객체로 위치 설정
mutableTransform.scale = { x: 5, y: 1, z: 5 }

// 각 축을 개별적으로 설정
mutableTransform.scale.x = 3
mutableTransform.scale.y = 3
mutableTransform.scale.z = 2
```

## 부모로부터 변환 상속

엔티티가 다른 엔티티 안에 중첩되면, 자식 엔티티는 부모의 컴포넌트를 상속합니다. 즉, 부모 엔티티가 위치, 스케일 또는 회전이 설정되어 있으면 자식도 영향을 받습니다. 자식 엔티티의 위치, 회전, 스케일 값은 부모의 값을 덮어쓰지 않고, 대신 누적됩니다.

다음의 `parent` 필드를 자식 엔티티의 `Transform` 컴포넌트를 추가해야 합니다.

부모 엔티티가 스케일 조정되어 있으면, 자식의 모든 위치 값도 함께 스케일 조정됩니다.

```ts
// 엔티티 생성
const parentEntity = engine.addEntity()
const childEntity = engine.addEntity()

// 부모용 Transform 생성
Transform.create(parentEntity, {
	position: Vector3.create(3, 1, 1),
	scale: Vector3.create(0.5, 0.5, 0.5),
})

// 자식용 Transform을 생성하고, 자식으로 할당
Transform.create(childEntity, {
	position: Vector3.create(0, 1, 0),
	parent: parentEntity,
})
```

이 예제에서는 부모가 그 스케일을 가지므로 자식 엔티티는 0.5로 축소됩니다. 자식 엔티티의 위치 역시 부모를 기준으로 상대적입니다. 부모의 위치와 자식의 위치를 합해야 합니다. 이 경우 부모가 절반 크기로 스케일되어 있으므로 자식의 변환도 비례해서 축소됩니다. 절대값으로 보면 자식은 `{ x: 3, y: 1.5, z: 1 }`에 위치합니다. 부모에 `회전`가 있다면, 이는 자식이 이동하는 축을 바꾸므로 자식의 최종 위치에도 영향을 줍니다.

자식 엔티티에 `위치` 가 Transform에 없으면 기본값은 `0,0,0`이며, 이 경우 부모와 같은 위치에 있게 됩니다.

형태 컴포넌트가 없는 보이지 않는 엔티티를 부모로 사용해 다른 엔티티들을 묶을 수 있습니다. 이 엔티티는 렌더링된 씬에서는 보이지 않지만, 자식들을 그룹화하고 그 모두에 변환을 적용하는 데 사용할 수 있습니다.

{% hint style="warning" %}
**📔 참고**: 계층 구조에 순환이 생기지 않도록 하세요. 엔티티가 자기 자신의 조상이 되는 경우입니다. SDK는 이런 순환을 감지하여 관련된 엔티티 이름이 포함된 경고를 기록합니다. 부모 관계를 수정하기 전까지 영향을 받은 엔티티들은 올바른 위치에 배치되지 않습니다.
{% endhint %}

## 엔티티를 아바타에 연결하기

엔티티를 플레이어에 연결하는 방법은 세 가지가 있습니다:

* 다음의 자식으로 만듭니다. **아바타 엔티티**
* 다음의 자식으로 만듭니다. **카메라 엔티티**
* 다음을 사용하세요 **AvatarAttach 컴포넌트**

아바타에 엔티티를 연결하는 가장 간단한 방법은 부모를 [예약된 엔티티](/creator/content-creator-ko/sdk7/architecture/entities-components.md#reserved-entities) `engine.PlayerEntity`로 설정하는 것입니다. 그러면 엔티티는 플레이어의 위치와 함께 이동합니다.

```ts
let childEntity = engine.addEntity()

MeshRenderer.setCylinder(childEntity)

Transform.create(childEntity, {
	scale: Vector3.create(0.2, 0.2, 0.2),
	position: Vector3.create(0, 0.4, 0),
	parent: engine.PlayerEntity,
})
```

엔티티를 [예약된 엔티티](/creator/content-creator-ko/sdk7/architecture/entities-components.md#reserved-entities) `engine.CameraEntity`로 설정할 수도 있습니다. 1인칭에서 카메라 엔티티를 사용할 때 연결된 엔티티는 카메라의 움직임을 따라갑니다. 예를 들어 총의 3D 모델을 카메라가 위를 보더라도 항상 화면에 보이게 유지하는 데 이상적입니다.

```ts
let childEntity = engine.addEntity()

MeshRenderer.setCylinder(childEntity)

Transform.create(childEntity, {
	scale: Vector3.create(0.2, 0.2, 0.2),
	position: Vector3.create(0, 0.4, 0),
	parent: engine.CameraEntity,
})
```

오브젝트를 아바타의 뼈 중 하나에 붙여 아바타 애니메이션과 함께 움직이게 하려면, 엔티티에 `AvatarAttach` 컴포넌트를 추가하세요.

아바타에서 서로 다른 앵커 포인트를 선택할 수 있으며, 이들 대부분은 플레이어의 스켈레톤에 연결되어 플레이어의 애니메이션을 따라갑니다. 예를 들어 오른손 앵커 포인트를 사용하면, 연결된 엔티티는 플레이어가 달리면서 팔을 흔들거나 휘두를 때 아바타가 손에 엔티티를 들고 있는 것처럼 함께 움직입니다.

```ts
// avatarId가 설정되지 않으면 기본적으로 engine.PlayerEntity가 사용되므로, 주 플레이어에 연결
AvatarAttach.create(myEntity, {
	anchorPointId: AvatarAnchorPointType.AAPT_NAME_TAG,
})

// ID로 플레이어에 연결
AvatarAttach.create(myEntity, {
	avatarId: '0xAAAAAAAAAAAAAAAAA',
	anchorPointId: AvatarAnchorPointType.AAPT_NAME_TAG,
})
```

다음의 `AvatarAttach` 컴포넌트를 생성할 때는 아래 데이터를 포함한 객체를 전달하세요:

* `avatarId`: *선택 사항* 연결할 플레이어의 ID입니다. 이는 Ethereum 지갑에 연결된 플레이어의 경우 플레이어의 Ethereum 주소와 동일합니다. 지정하지 않으면 로컬 플레이어의 아바타에 엔티티가 연결됩니다.
* `anchorPointId`: 엔티티를 아바타 스켈레톤의 어느 앵커 포인트에 붙일지 나타내며, 열거형 `AvatarAnchorPointType`.

{% hint style="warning" %}
**📔 참고**: 씬의 모든 플레이어가 동일한 플레이어에 연결된 오브젝트를 보게 하고 싶다면, 예를 들어 Player A가 오브젝트를 집어서 왼손에 들고 있는 것을 모두가 보게 하려면 `avatarId`에 값을 제공해야 합니다. 지정하지 않으면 모든 플레이어는 각자의 아바타에 연결된 오브젝트를 보게 됩니다.
{% endhint %}

다음 예제는 특정 아바타에 연결된 엔티티를 배치하며, 다른 모든 플레이어는 그것이 같은 아바타에 연결된 것으로 보게 됩니다.

```ts
import { getPlayer } from '@dcl/sdk/src/players'
import { AvatarAnchorPointType, AvatarAttach, engine, Entity } from '@dcl/sdk/ecs'
import { syncEntity } from '@dcl/sdk/network'

async function attachToPlayer(){

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

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

  let entity = engine.addEntity()

  AvatarAttach.create(entity, {
    avatarId: userData.userId,
    anchorPointId: AvatarAnchorPointType.AAPT_RIGHT_HAND,
  })

  // 기타 컴포넌트

  syncEntity(entity, [AvatarAttach.componentId])

}
```

다음 앵커 포인트를 `AvatarAnchorPointType` 열거형에서 사용할 수 있습니다:

* `AAPT_RIGHT_HAND`: 플레이어의 오른손에 고정
* `AAPT_LEFT_HAND`: 플레이어의 왼손에 고정
* `AAPT_HEAD`: 플레이어 머리의 중앙에 고정.
* `AAPT_NECK`: 플레이어 목의 기저부에 고정.
* `AAPT_SPINE`: 척추 상단에 고정.
* `AAPT_SPINE1`: 척추 중간 부분에 고정.
* `AAPT_SPINE2`: 척추 하단 부분에 고정.
* `AAPT_HIP`: 엉덩이뼈에 고정.
* `AAPT_LEFT_SHOULDER`: 왼쪽 어깨에 고정.
* `AAPT_LEFT_ARM`: 어깨 높이의 왼쪽 첫 번째 팔뼈에 고정.
* `AAPT_LEFT_FOREARM`: 왼쪽 아래팔뼈에 고정.
* `AAPT_LEFT_HAND_INDEX`: 왼쪽 검지 끝에 고정.
* `AAPT_RIGHT_SHOULDER`: 오른쪽 어깨에 고정.
* `AAPT_RIGHT_ARM`: 어깨 높이의 오른쪽 첫 번째 팔뼈에 고정.
* `AAPT_RIGHT_FOREARM`: 오른쪽 아래팔뼈에 고정.
* `AAPT_RIGHT_HAND_INDEX`: 오른쪽 검지 끝에 고정.
* `AAPT_LEFT_UP_LEG`: 왼쪽 다리의 위쪽 다리뼈에 고정.
* `AAPT_LEFT_LEG`: 왼쪽 다리의 아래쪽 다리뼈에 고정.
* `AAPT_LEFT_FOOT`: 왼쪽 다리의 발목에 고정.
* `AAPT_LEFT_TOE_BASE`: 왼쪽 다리의 발가락 끝에 고정.
* `AAPT_RIGHT_UP_LEG`: 오른쪽 다리의 위쪽 다리뼈에 고정.
* `AAPT_RIGHT_LEG`: 오른쪽 다리의 아래쪽 다리뼈에 고정.
* `AAPT_RIGHT_FOOT`: 오른쪽 다리의 발목에 고정.
* `AAPT_RIGHT_TOE_BASE`: 오른쪽 다리의 발가락 끝에 고정.
* `.AAPT_NAME_TAG`: 플레이어 이름표 바로 위에 떠 있으며, 플레이어 애니메이션의 영향을 받지 않습니다.

  > 참고: 이름표 높이는 플레이어가 착용한 웨어러블의 높이에 따라 동적으로 조정됩니다. 따라서 높은 모자를 쓴 플레이어는 다른 플레이어보다 이름표가 조금 더 높게 표시됩니다.
* `AAPT_POSITION` *사용 중단됨*: 플레이어의 전체 위치입니다. 이는 플레이어의 발보다 0.8 높은 위치에 나타납니다.

  >

{% hint style="warning" %}
\> \*\*📔 참고\*\*: \`AAPT\_POSITION\`은 사용 중단되었습니다. 플레이어의 전체 위치를 따르려면 엔티티를 Avatar Entity의 자식으로 만드는 것이 가장 좋습니다. 이 섹션의 시작 부분에 있는 예시를 참조하세요. >
{% endhint %}

{% hint style="info" %}
**💡 팁**: 이러한 값을 사용하려면 다음과 같이 작성하세요 `AvatarAnchorPointType.` 그러면 VS Code가 드롭다운에 전체 옵션 목록을 표시합니다.
{% endhint %}

![](https://3980763956-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-206945bba419a58cd6fe54c557cc6e5d75e1bb86%2Favatar-attach-points.png?alt=media\&token=bd194d22-a304-4254-b739-b25cdf372497)

엔티티 렌더링은 씬의 각 인스턴스에서 로컬로 결정됩니다. 한 플레이어에 엔티티를 부착해도 그 플레이어를 보고 있는 다른 플레이어들에게는 보이지 않습니다. 엔티티가 기본 로컬 플레이어에 부착되면, 각 플레이어는 그 엔티티가 자신의 아바타에 부착된 것처럼 보이게 됩니다.

{% hint style="warning" %}
**📔 참고**: 아바타에 부착된 엔티티는 렌더링되기 위해 씬 경계 안에 있어야 합니다. 플레이어가 씬 밖으로 나가면, 부착된 엔티티는 플레이어가 다시 들어올 때까지 렌더링이 중지됩니다. 스마트 웨어러블에는 이 제한이 없습니다.
{% endhint %}

이 `AvatarAttach` 컴포넌트가 다음의 값을 덮어씁니다 `Transform` 컴포넌트에 넣은 값은 모두 `Transform` 플레이어의 Transform에 대한 엔티티의 상대 위치로 대체되며, 플레이어가 이동하고 애니메이션할 때 이 값들은 프레임마다 업데이트됩니다.

아바타의 앵커 포인트에서의 오프셋, 또는 다른 회전이나 스케일로 엔티티를 배치해야 한다면, 부모 엔티티를 통해 이렇게 하세요.

1. 컴포넌트만 가진 보이지 않는 엔티티를 만드세요. `Transform` 및 `AvatarAttach` 해당 컴포넌트의 `Transform` 값은 플레이어가 이동함에 따라 덮어써집니다
2. 연결하려는 엔티티를 이 부모의 자식으로 설정하세요. 해당 `Transform` 값은 앵커 포인트로부터의 오프셋을 나타낼 수 있습니다.

```ts
// 부모 엔티티 생성
const parentEntity = engine.addEntity()

// 부모 엔티티를 플레이어에 연결
AvatarAttach.create(parentEntity, {
	anchorPointId: AvatarAnchorPointType.AAPT_NAME_TAG,
})

// 자식 엔티티 생성
let childEntity = engine.addEntity()

MeshRenderer.setCylinder(childEntity)

Transform.create(childEntity, {
	scale: Vector3.create(0.2, 0.2, 0.2),
	position: Vector3.create(0, 0.4, 0),
	parent: parentEntity,
})
```

{% hint style="warning" %}
**📔 참고**: 연결된 엔티티에 콜라이더가 있으면, 이 콜라이더가 플레이어의 이동을 막거나 떨림 효과를 일으킬 수 있습니다. 연결된 엔티티의 콜라이더에서 물리 레이어를 비활성화하는 것이 좋을 수 있습니다. 참조: [충돌 레이어](/creator/content-creator-ko/sdk7/3d/colliders.md#collision-layers)
{% endhint %}

{% hint style="warning" %}
**📔 참고**: 자식 엔티티가 있고 그 엔티티의 전역 Position 및/또는 Rotation을 알고 싶다면, 다음을 사용할 수 있습니다. `getWorldPosition` 과 `getWorldRotation` 함수들을 사용할 수 있습니다. 다음에서 확인할 수 있습니다: [전역 위치와 회전 구하기](#getting-global-position-and-rotation-of-an-entity) 섹션.
{% endhint %}

### 다른 플레이어에 연결

다음을 사용할 수 있습니다 `AvatarAttach` 컴포넌트를 사용하여 엔티티를 다른 플레이어에 연결합니다. 이를 위해서는 플레이어의 ID를 알아야 합니다.

다른 플레이어의 아바타에 엔티티를 연결하려면 필드에 사용자의 ID를 제공해야 합니다 `avatarId`. 이를 얻는 [다양한 방법이](/creator/content-creator-ko/sdk7/interactivity/user-data.md#get-player-data) 있습니다.

{% hint style="warning" %}
**📔 참고**: 이더리움 지갑에 연결된 플레이어의 경우, 그들의 `userId` 값은 이더리움 주소와 같습니다.
{% endhint %}

다음을 가져오세요 `userId` 다른 모든 주변 플레이어에 대해 `getPlayer()`

```ts
executeTask(async () => {
	for (const [entity, data] of engine.getEntitiesWith(PlayerIdentityData)) {
		console.log('Player id: ', data.address)
	}
})
```

다음과 함께 사용하면 `AvatarAttach`, 씬의 다른 모든 플레이어의 머리 위에 떠 있는 큐브를 추가하는 데 다음 코드를 사용할 수 있습니다:

```ts
executeTask(async () => {
        for (const [entity, data] of engine.getEntitiesWith(PlayerIdentityData)) {
            const myEntity = engine.addEntity()
            MeshRenderer.setBox(myEntity)
            AvatarAttach.create(myEntity, {
                anchorPointId: AvatarAnchorPointType.AAPT_LEFT_HAND,
                avatarId: data.address,
            })
        }
    })
```

다른 사용자의 ID를 가져오는 다른 방법은 다음에서 확인하세요: [플레이어 데이터 가져오기](/creator/content-creator-ko/sdk7/interactivity/user-data.md#get-player-data).

## 씬 경계

씬 안의 모든 엔티티는 씬 경계 안에 들어가야 합니다. 해당 경계 밖은 다른 플레이어가 소유한 토지 구획이기 때문입니다.

미리보기를 실행할 때 모델의 일부가 이 한계를 넘어가면, 넘어간 부분은 잘려 나가 미리보기 실행 시와 게시된 씬 모두에서 렌더링되지 않습니다.

씬 안의 엔티티 위치는 이동하는 동안 지속적으로 확인됩니다. 엔티티가 씬을 벗어났다 다시 들어오면 제거되었다가 다시 정상적으로 렌더링됩니다.

씬 바닥의 그리드는 씬의 경계를 보여 주며, 기본적으로는 0부터 16까지의 *x* 과 *z* 축과 *y* 축에서 최대 20까지입니다. 엔티티를 지하, 즉 0보다 낮은 *y* 축입니다.

{% hint style="info" %}
**💡 팁**: 씬에 더 많은 필지가 필요하다면, 프로젝트의 `scene.json` 파일에 추가할 수 있습니다. 자세한 내용은 [씬 메타데이터](/creator/content-creator-ko/sdk7/kinds-of-projects/scene-metadata.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-ko/sdk7/3d/entity-positioning.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.
