> 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/user-data.md).

# 사용자 데이터

플레이어가 씬과 상호작용할 때 데이터를 가져오세요.

## 플레이어 위치 및 회전

다음을 사용하세요 `PlayerEntity` 와 `CameraEntity` 플레이어의 위치와 회전을 확인하려면, 해당 `Transform` 컴포넌트가 있는 엔티티 모두에 동일하게 적용됩니다.

```ts
function getPlayerPosition() {
	if (!Transform.has(engine.PlayerEntity)) return
	if (!Transform.has(engine.CameraEntity)) return

	//플레이어 위치
	const playerPos = Transform.get(engine.PlayerEntity).position

	//플레이어 회전
	const playerRot = Transform.get(engine.PlayerEntity).rotation

	//카메라 위치
	const CameraPos = Transform.get(engine.CameraEntity).position

	//카메라 회전
	const CameraRot = Transform.get(engine.CameraEntity).rotation

	console.log('playerPos: ', playerPos)
	console.log('playerRot: ', playerRot)
	console.log('cameraPos: ', CameraPos)
	console.log('cameraRot: ', CameraRot)
}

engine.addSystem(getPlayerPosition)
```

* **PlayerEntity 위치**: 아바타의 위치로, 가슴 높이입니다. 지면에서 약 0.88미터 위입니다.
* **PlayerEntity 회전**: 아바타가 바라보는 방향을 쿼터니언으로 표현한 값입니다.
* **CameraEntity 위치**:
  * 1인칭에서는: 아바타의 위치와 같지만 눈높이입니다. 지면에서 약 1.75미터 위입니다.
  * 3인칭에서는: 카메라 움직임에 따라 달라질 수 있습니다.
* **PlayerEntity 회전**:
  * 1인칭에서는: 아바타가 바라보는 방향과 비슷하며, 쿼터니언으로 표현됩니다. 플레이어의 회전과 약간 다르게 반올림될 수 있습니다.
  * 3인칭에서는: 카메라 움직임에 따라 달라질 수 있습니다.

{% hint style="warning" %}
**📔 참고**: 다음을 참조하지 마세요 `engine.PlayerEntity` 또는 `engine.CameraEntity` 초기 씬 로딩 시에, 엔티티가 아직 초기화되지 않았으면 오류가 발생할 수 있기 때문입니다. 이 문제를 피하려면, 다음 안에서 사용하세요 `main()` 함수, 또는 다음에 의해 간접적으로 호출되는 함수 안에서 사용하세요 `main()`. 또한 동작을 async [`executeTask` 블록](/creator/content-creator-ko/sdk7/programming-patterns/async-functions.md#the-executetask-function).

또 다른 방법은 시스템 내부에서 이러한 엔티티를 참조하는 것입니다. 씬이 이미 올바르게 초기화된 뒤에 시스템의 첫 실행이 호출되므로, 그곳에서는 항상 사용할 수 있습니다.
{% endhint %}

## 모든 플레이어 가져오기

씬의 모든 플레이어는 `Transform` 컴포넌트를 가지고 있습니다. 이 컴포넌트는 아바타에서 읽기 전용입니다. 모든 플레이어의 위치를 가져오려면, [다음을 가진 모든 엔티티를 순회하세요](/creator/content-creator-ko/sdk7/interactivity/user-data.md) a `PlayerIdentityData` 컴포넌트를 추가해야 합니다.

```ts
import { PlayerIdentityData } from '@dcl/sdk/ecs'

for (const [entity, data, transform] of engine.getEntitiesWith(
	PlayerIdentityData,
	Transform
)) {
	console.log('Player data: ', { entity, data, transform })
}
```

위 코드는 다음을 가진 모든 엔티티를 순회합니다 `Transform` 와 하나의 `PlayerIdentityData` 컴포넌트의 데이터를 로그로 출력합니다. 같은 방법으로 모든 플레이어의 사용 가능한 데이터를 가져올 수 있습니다.

다음 [이벤트 리스너](/creator/content-creator-ko/sdk7/interactivity/event-listeners.md#player-locks-or-unlocks-cursor) 새 플레이어가 씬에 들어올 때 이를 감지하고 반응하는 방법은

## 플레이어 데이터 가져오기

다음을 사용하세요 `getPlayer()` 현재 플레이어나 씬의 다른 플레이어에 대한 데이터를 가져오려면

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

export function main() {
	createCube(5, 1, 5)

	let myPlayer = getPlayer()

	if (myPlayer) {
		console.log('이름 : ', myPlayer.name)
		console.log('사용자 ID : ', myPlayer.userId)
	}
}
```

`getPlayer()` 다음을 반환합니다:

* `name`: *(문자열)* 다른 사람들이 월드에서 보는 플레이어의 사용자 이름
* `userId`: *(문자열)* 플레이어를 식별하는 문자열입니다. 지갑에 연결된 플레이어의 경우, 지갑 주소를 소문자로 표기한 값입니다. 게스트 계정의 경우 로컬에서 생성된 식별자입니다.
* `isGuest`: *(불리언)* 플레이어에게 공개 키가 있는지 나타냅니다. *참* 플레이어가 공개 키가 없는 게스트 계정인 경우.
* `위치`: *(Vector3)* 씬에서 아바타의 위치입니다.
* `아바타`: 플레이어의 기본 아바타와 외형에 대한 데이터를 담은 중첩 객체입니다.
* `wearables`: 플레이어가 현재 착용 중인 각 웨어러블의 식별자 배열입니다. 예를 들면 `urn:decentraland:off-chain:base-avatars:green_hoodie`. NFT여도 모든 웨어러블은 비슷한 식별자를 가집니다.
* `emotes`: 플레이어가 현재 빠른 액세스 휠에 장착한 각 이모트의 식별자 배열입니다.
* `엔티티`: 플레이어 엔티티에 대한 참조입니다. 다른 함수에 전달하거나 여기에 사용자 정의 컴포넌트를 추가할 때 유용합니다.

이 `아바타` 객체에는 다음 중첩 정보가 포함됩니다:

* `bodyShapeUrn`: 아바타의 일반적인 체형 식별자입니다. 다음 중 하나입니다 `urn:decentraland:off-chain:base-avatars:BaseFemale` 여성용 또는 `urn:decentraland:off-chain:base-avatars:BaseMale` 남성용.
* `skinColor`: 플레이어의 피부색으로, `Color3`
* `eyesColor`: 플레이어의 눈 색깔로, `Color3`
* `hairColor`: 플레이어의 머리색으로, `Color3`
* `name`: 플레이어 이름입니다.

{% hint style="warning" %}
**📔 참고**: 씬의 첫 프레임에서는 로딩 시간에 따라 플레이어 데이터를 사용할 수 없을 수 있습니다. 데이터가 반환되었는지 확인하고, 그렇지 않으면 몇 밀리초 후에 다시 시도해야 합니다.
{% endhint %}

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

export function main() {
	createCube(5, 1, 5)

	let myPlayer = getPlayer()

	if (myPlayer) {
		console.log('게스트 여부: ', myPlayer.isGuest)
		console.log('이름 : ', myPlayer.name)
		console.log('사용자 ID : ', myPlayer.userId)
		console.log('아바타 모양 : ', myPlayer.position)
		console.log('아바타 모양 : ', myPlayer.avatar?.bodyShapeUrn)
		console.log('아바타 눈 색깔 : ', myPlayer.avatar?.eyesColor)
		console.log('아바타 머리 색깔 : ', myPlayer.avatar?.hairColor)
		console.log('착용 중인 웨어러블 : ', myPlayer.wearables)
		console.log('사용 가능한 이모트 : ', myPlayer.emotes)
	}
}
```

씬의 현재 플레이어와 다른 특정 플레이어의 데이터를 가져오려면 다음을 실행하세요 `getPlayer()` 다음이 있는 객체와 함께 `userId` 속성으로 정의됩니다.

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

for (const [entity, data, transform] of engine.getEntitiesWith(
	PlayerIdentityData,
	Transform
)) {
	let player = getPlayer({ userId: data.address })
	console.log('플레이어 : ', player?.name)
}
```

위 스니펫은 다음을 가진 모든 엔티티를 순회합니다 `PlayerIdentityData` 컴포넌트를 가진 모든 아바타 엔티티를 의미합니다. 그런 다음 다음을 실행합니다 `getPlayer()` 해당 엔티티에 대해.

`getPlayer()` 현재 같은 씬에 서 있는 플레이어의 데이터만 가져올 수 있습니다. 반드시 시야 범위 안에 있을 필요는 없지만, 같은 comms island에 연결되어 있어야 합니다. 미리보기에서 시험해보려면 두 번째 탭을 열고 다른 계정으로 로그인한 뒤, 두 플레이어를 모두 씬 안에 서 있게 하세요.

{% hint style="warning" %}
**📔 참고**: 사용자 ID는 항상 소문자여야 합니다. 지갑 주소를 복사할 때는 모든 문자가 소문자인지 확인하세요.
{% endhint %}

## 모든 플레이어의 데이터

어떤 플레이어든 정보를 얻으려면 다음을 수행하세요 [REST API 호출](/creator/content-creator-ko/sdk7/networking/network-connections.md#call-a-rest-api) 콘텐츠 서버에 대해.

이 정보는 다음 URL에 노출되며, URL 파라미터에 플레이어의 사용자 ID를 추가합니다.

`https://peer.decentraland.org/lambdas/profile/<player user id>`

{% hint style="info" %}
**💡 팁**: 브라우저에서 URL을 열어 응답 구조를 확인해 보세요.
{% endhint %}

이 API에서 다음 정보를 사용할 수 있습니다:

* `displayName`: *(문자열)* 다른 사람들이 월드에서 보는 플레이어의 사용자 이름
* `userId`: *(문자열)* 플레이어를 식별하는 UUID 문자열입니다. 플레이어에게 공개 키가 있으면 이 필드는 공개 키와 같은 값이 됩니다.
* `hasConnectedWeb3`: *(불리언)* 플레이어에게 공개 키가 있는지 나타냅니다. *참* 플레이어가 이를 가지고 있으면
* `publicKey`: *(문자열)* 플레이어의 이더리움 지갑의 공개 키입니다. 플레이어가 연결된 지갑 없이 게스트로 로그인한 경우, 이 필드는 `null`.
* `아바타`: 플레이어 외형에 대한 데이터를 담은 중첩 객체입니다.
* `version`: *(숫자)* 플레이어가 설정을 변경할 때마다 1씩 증가하는 버전 번호입니다. 충돌하는 데이터를 만났을 때 어떤 버전이 더 최신인지 알기 위해 사용하세요.

{% hint style="warning" %}
**📔 참고**: 플레이어와 관련된 모든 이더리움 거래에는 항상 `publicKey` 필드를 사용하고, 다음 대신 `userId`, 존재하지 않는 지갑을 다루지 않기 위해서입니다.
{% endhint %}

이 `아바타` 객체에는 다음 중첩 정보가 포함됩니다:

* `wearables`: `WearableId[]` 플레이어가 현재 착용 중인 각 웨어러블의 식별자 배열입니다. 예를 들면 `urn:decentraland:off-chain:base-avatars:green_hoodie`. NFT여도 모든 웨어러블은 비슷한 식별자를 가집니다.
* `bodyShape`: 아바타의 일반적인 체형 식별자입니다. 다음 중 하나입니다 `urn:decentraland:off-chain:base-avatars:BaseFemale` 여성용 또는 `urn:decentraland:off-chain:base-avatars:BaseMale` 남성용.
* `skin`: 다음을 가진 객체입니다 `color` 필드이며, 플레이어의 피부색을 다음 형식으로 담고 있습니다 `{ r, g, b, a }` 0부터 1 사이의 숫자입니다.
* `hair`: 다음을 가진 객체입니다 `color` 필드이며, 플레이어의 머리색을 다음 형식으로 담고 있습니다 `{ r, g, b, a }` 0부터 1 사이의 숫자입니다.
* `eyes`: 다음을 가진 객체입니다 `color` 필드이며, 플레이어의 눈 색깔을 다음 형식으로 담고 있습니다 `{ r, g, b, a }` 0부터 1 사이의 숫자입니다.
* `snapshots`: 다양한 해상도의 플레이어 .jpg 이미지의 base64 표현을 담은 중첩 객체입니다.
  * `face256`: *문자열* 256x256픽셀 이미지로 된 플레이어의 얼굴입니다.
  * `body`: *문자열* 서 있는 플레이어의 전체 해상도 이미지로, 512x1024픽셀입니다.

{% hint style="danger" %}
**❗경고** 아바타 스냅샷은 향후 폐기되며 더 이상 아바타 데이터의 일부로 반환되지 않습니다. 권장되는 방법은 다음을 사용하는 것입니다 `AvatarTexture` 대신 사용하세요, 다음을 참조하세요 [아바타 초상화](/creator/content-creator-ko/sdk7/3d/materials.md#avatar-portraits).
{% endhint %}

와 달리 `getPlayer()`, 이 옵션은 현재 같은 씬에 있는 플레이어뿐 아니라 같은 서버에 있는 플레이어로도 제한되지 않습니다. 이 방법을 사용하면 과거에 서버에 로그인한 모든 플레이어의 데이터를 가져올 수 있습니다.

조회하려는 플레이어가 연결된 서버를 알고 있다면, 해당 특정 서버에 요청을 보내 더 최신 데이터를 얻을 수 있습니다. 예를 들어 플레이어가 옷을 바꾸면 이 정보는 플레이어의 서버에는 즉시 반영되지만, 다음으로 전파되기까지는 몇 분 정도 `peer.decentraland.org` 서버.

`https://<player server>/lambdas/profile/<player user id>`

{% hint style="info" %}
**💡 팁**: 현재 플레이어의 서버는 다음을 호출하여 얻을 수 있습니다 `getRealm()` 그리고 다음을 읽어서 `realmInfo.baseUrl` 응답의 필드를.
{% endhint %}

이 예시는 다음을 결합합니다 `myProfile.userId` 과 `getRealm()` 플레이어가 있는 서버에서 직접 플레이어 데이터를 가져옵니다:

```ts
import { getRealm } from '~system/Runtime'
import { myProfile } from '@dcl/sdk/network'

async function fetchPlayerData() {
	const { realmInfo } = await getRealm({})
	if (!realmInfo) return

	const url = `${realmInfo.baseUrl}/lambdas/profile/${myProfile.userId}`
	console.log('URL 사용: ', url)

	try {
		const response = await fetch(url)
		const json = await response.json()

		console.log('전체 응답: ', json)
		console.log('플레이어가 착용 중인 것 :', json.avatars[0].avatar.wearables)
	} catch {
		console.log('플레이어 데이터를 가져오는 동안 오류가 발생했습니다')
	}
}

fetchPlayerData()
```

## 플레이어 데이터 컴포넌트

다음을 사용하는 대신 `getPlayer()`각 플레이어 엔티티에 데이터를 저장하는 일련의 컴포넌트에서 직접 데이터를 읽을 수 있습니다. 다음 컴포넌트가 있습니다:

* `PlayerIdentityData`플레이어 주소와 다음을 저장합니다 `isGuest` 게스트 계정을 표시하는 속성
* `AvatarBase`기본 아바타에 대한 데이터를 저장합니다. 여기에는 다음이 포함됩니다:
  * `name`: 플레이어 이름입니다.
  * `bodyShapeUrn`남성 또는 여성 체형에 해당하는 ID입니다.
  * `skinColor`: 플레이어의 피부색으로, `Color3`
  * `eyesColor`: 플레이어의 눈 색깔로, `Color3`
  * `hairColor`: 플레이어의 머리색으로, `Color3`
* `AvatarEquippedData`착용 중인 웨어러블과 이모트 목록입니다.
  * `wearableUrns`플레이어가 현재 장착한 웨어러블 목록입니다.
  * `emoteUrns`플레이어가 현재 빠른 액세스 휠에 장착한 이모트 목록입니다.
* `AvatarEmoteCommand`플레이어가 현재 재생 중인 이모트에 대한 정보입니다. 다음이 포함됩니다:
  * `emoteUrn`플레이어가 씬에 들어온 이후 마지막으로 재생한 이모트의 URN입니다
  * `loop`이모트가 반복 재생 중이면 참입니다
  * `타임스탬프`이 이모트가 실행된 시간입니다

```ts
for (const [entity, data, base, attach, transform] of engine.getEntitiesWith(
	PlayerIdentityData,
	AvatarBase,
	AvatarEquippedData,
	Transform
)) {
	console.log('플레이어 데이터: ', { entity, data, transform, base, attach })
}
```

{% hint style="warning" %}
**📔 참고**이 컴포넌트들은 모두 읽기 전용입니다. 씬에서 값을 변경할 수 없습니다.
{% endhint %}

## 휴대형 경험 가져오기

휴대형 경험은 본질적으로 토지 파셀에 제한되지 않는 씬입니다. 플레이어는 Decentraland 어디를 가든 이를 함께 가져갈 수 있어, 세상 위에 새로운 콘텐츠 레이어를 추가합니다. 스마트 웨어러블이 휴대형 경험의 예입니다. 스마트 웨어러블은 경쟁 게임에서 치팅으로 간주될 수 있는 능력을 플레이어에게 부여할 수 있으므로, 플레이어가 이런 것 중 하나를 착용했는지 알고 싶을 수 있습니다. 예를 들어 플랫폼 게임에서 제트팩을 착용한 플레이어는 다른 사람들에 비해 매우 불공평한 이점을 가집니다.

씬 제작자로서 휴대형 경험을 착용한 플레이어가 씬에서 할 수 있는 일을 제한하고 싶을 수 있습니다. 다음을 사용하세요 `getPortableExperiencesLoaded()` 플레이어에게 현재 활성화된 휴대형 경험이 있는지 확인하려면

```ts
import { getPortableExperiencesLoaded } from '~system/PortableExperiences'

executeTask(async () => {
	let portableExperiences = await getPortableExperiencesLoaded({})
	console.log(portableExperiences.loaded)
})
```

`getPortableExperiencesLoaded()` 객체 배열을 반환하며, 각 객체에는 다음이 포함됩니다 `id` 속성입니다. 웨어러블의 경우 id는 웨어러블의 URN입니다.

## 플레이어의 웨어러블에 대한 자세한 정보 가져오기

이 `getPlayer()` 함수는 각 웨어러블에 대한 정보 없이 웨어러블 ID 목록만 반환합니다. 특정 카테고리의 웨어러블(예: 모자)이나 특정 희귀도(예: Mythic)의 웨어러블을 확인하고 싶을 수 있는데, 이를 위해서는 플레이어의 웨어러블에 대한 더 자세한 정보를 가져와야 합니다.

다음을 수행하세요 [REST API 호출](/creator/content-creator-ko/sdk7/networking/network-connections.md#call-a-rest-api) 다음 URL로 요청하여 현재 사용 가능한 모든 웨어러블의 전체 최신 목록과 각 항목의 세부 정보를 가져오세요.

`${playerRealm.realmInfo.baseUrl}/lambdas/collections/wearables-by-owner/${userData.userId}?includeDefinitions`

{% hint style="warning" %}
**📔 참고**이 URL을 구성하려면 realm을 얻어야 합니다(아마도 다음을 사용해 `getRealm()`) 그리고 플레이어 ID를 얻어야 합니다(아마도 다음을 사용해 `getPlayer()`)
{% endhint %}

이 기능은 플레이어 정보 가져오기와 함께 사용할 수 있습니다. 예를 들어 플레이어가 할로윈 컬렉션의 웨어러블을 착용했을 때만, 또는 다음 희귀도의 웨어러블을 착용했을 때만 장소에 들어오도록 허용할 수 있습니다 *전설* 희귀도.

{% hint style="info" %}
**💡 팁**: 브라우저에서 URL을 열어 응답 구조를 확인해 보세요.
{% endhint %}

```ts
import { getPlayer } from '@dcl/sdk/src/players'
import { getRealm } from '~system/Runtime'

async function fetchWearablesData() {
	try {
		let userData = getPlayer()
		const realm = await getRealm({})
		if (!userData || !realm.realmInfo) return

		const url =
			`${realm.realmInfo?.baseUrl}/lambdas/collections/wearables-by-owner/${userData.userId}?includeDefinitions`.toString()
		console.log('URL 사용: ', url)

		let response = await fetch(url)
		let json = await response.json()

		console.log('전체 응답: ', json)
	} catch {
		console.log('웨어러블 데이터를 가져오는 동안 오류가 발생했습니다')
	}
}

executeTask(fetchWearablesData)
```

{% hint style="info" %}
**💡 팁**: 다음 API에서 특정 웨어러블에 대한 더 많은 정보도 가져올 수 있습니다 [다음 API](https://decentraland.github.io/catalyst-api-specs/#tag/Lambdas/operation/searchWearables).
{% endhint %}

## 플레이어의 카메라 모드 확인

플레이어는 Decentraland를 탐험할 때 1인칭 또는 3인칭 카메라를 사용할 수 있습니다. 다음 값으로 플레이어가 어떤 모드를 사용하는지 확인하세요 `CameraMode` 컴포넌트의 `engine.CameraEntity` 엔티티를 사용해 플레이어 카메라 위치에서 앞으로 레이를 추적합니다.

```ts
function checkCameraMode() {
	if (!CameraMode.has(engine.CameraEntity)) return

	let cameraEntity = CameraMode.get(engine.CameraEntity)

	if (cameraEntity.mode == CameraType.CT_THIRD_PERSON) {
		플레이어가 3인칭 카메라를 사용 중입니다
	} else {
		플레이어가 1인칭 카메라를 사용 중입니다
	}
}

engine.addSystem(checkCameraMode)
```

{% hint style="warning" %}
**📔 참고**: 카메라 정보는 씬을 실행 중인 현재 플레이어에게만 사용할 수 있습니다. 다른 플레이어의 카메라 데이터는 조회할 수 없습니다.
{% endhint %}

카메라 모드는 다음의 값을 사용합니다 `CameraType` enum입니다. 가능한 값은 다음과 같습니다:

* `CameraType.CT_FIRST_PERSON`
* `CameraType.CT_THIRD_PERSON`

이 `CameraMode` 컴포넌트의 `engine.CameraEntity` 읽기 전용이므로 이를 통해 플레이어의 카메라 모드를 강제로 변경할 수는 없습니다.

{% hint style="info" %}
**💡 팁**: 플레이어의 카메라 모드를 변경하려면 다음을 사용하세요 [카메라 수정 영역](/creator/content-creator-ko/sdk7/3d/camera.md#1st-and-3rd-person-camera-modes).
{% endhint %}

카메라 모드를 알면 이 모드에서 더 편한 방식에 맞춰 씬의 메커니즘을 세밀하게 조정하는 데 매우 유용합니다. 예를 들어 3인칭에서는 작은 대상을 클릭하기가 더 어렵습니다.

{% hint style="warning" %}
**📔 참고**: 다음을 참조하지 마세요 `engine.CameraEntity` 초기 씬 로딩 시에, 엔티티가 아직 초기화되지 않았으면 오류가 발생할 수 있기 때문입니다. 이 문제를 피하려면, 다음 안에서 사용하세요 `main()` 함수, 또는 다음에 의해 간접적으로 호출되는 함수 안에서 사용하세요 `main()`. 또한 동작을 async [`executeTask` 블록](/creator/content-creator-ko/sdk7/programming-patterns/async-functions.md#the-executetask-function).

또 다른 방법은 시스템 내부에서 이 엔티티를 참조하는 것입니다. 씬이 이미 올바르게 초기화된 뒤에 시스템의 첫 실행이 호출되므로, 항상 사용할 수 있습니다.
{% endhint %}

## 플레이어의 커서가 잠겨 있는지 확인

플레이어는 두 가지 커서 모드 사이를 전환할 수 있습니다: *잠금 커서* 모드로 카메라를 제어하거나 *잠금 해제 커서* 모드로 UI 위에서 커서를 자유롭게 움직입니다.

플레이어는 다음을 클릭하여 커서를 잠금 해제합니다 *마우스 오른쪽 버튼* 또는 다음 키를 누르거나 *Esc* 키를 누르고, 화면 어디든 클릭하면 커서를 다시 잠급니다.

다음 항목을 확인하세요. `PointerLock` 씬의 [카메라 엔티티의](/creator/content-creator-ko/sdk7/architecture/entities-components.md#reserved-entities) 를 통해 현재 커서 모드가 무엇인지 확인하세요.

```ts
export function main() {
	const isLocked = PointerLock.get(engine.CameraEntity).isPointerLocked
	console.log(isLocked)
}
```

다음 [이벤트 리스너](/creator/content-creator-ko/sdk7/interactivity/event-listeners.md#player-locks-or-unlocks-cursor) 커서 상태 변경에 쉽게 반응하는 방법을 보려면

플레이어의 커서 상태는 다음에 값을 써서 강제로 변경할 수도 있습니다 `isPointerLocked` 필드 `PointerLock` 의 컴포넌트 `engine.CameraEntity`. 참고: [커서 잠그기 또는 잠금 해제](/creator/content-creator-ko/sdk7/interactivity/button-events/click-events.md#lock-or-unlock-the-cursor) 예제를 참고하세요.

{% hint style="warning" %}
**📔 참고**: 다음을 참조하지 마세요 `engine.CameraEntity` 초기 씬 로딩 시에, 엔티티가 아직 초기화되지 않았으면 오류가 발생할 수 있기 때문입니다. 이 문제를 피하려면, 다음 안에서 사용하세요 `main()` 함수, 또는 다음에 의해 간접적으로 호출되는 함수 안에서 사용하세요 `main()`. 또한 동작을 async [`executeTask` 블록](/creator/content-creator-ko/sdk7/programming-patterns/async-functions.md#the-executetask-function).

또 다른 방법은 시스템 내부에서 이 엔티티를 참조하는 것입니다. 씬이 이미 올바르게 초기화된 뒤에 시스템의 첫 실행이 호출되므로, 항상 사용할 수 있습니다.
{% endhint %}

## 플레이어의 커서 위치 확인

다음을 사용하세요 `PrimaryPointerInfo` 컴포넌트를 다음에 `engine.RootEntity` 플레이어의 커서 위치를 가져오려면 사용하세요. 드래그 앤 드롭 상호작용, 스와이프 제스처 등의 메커니즘에 사용할 수 있습니다.

```ts
import { PrimaryPointerInfo } from '@dcl/sdk/ecs'

function CursorSystem() {
	const pointerInfo = PrimaryPointerInfo.get(engine.RootEntity)
	console.log(pointerInfo)
}

engine.addSystem(CursorSystem)
```

{% hint style="warning" %}
**📔 참고**: 다음을 참조하지 마세요 `engine.RootEntity` 초기 씬 로딩 시에는 엔티티가 아직 초기화되지 않았으면 오류가 발생할 수 있으므로, 이를 참조하지 마세요. 이 문제를 피하려면 항상 시스템 내부에서 엔티티를 참조하세요. 씬이 이미 올바르게 초기화된 뒤에 시스템의 첫 실행이 호출되므로, 항상 사용할 수 있습니다.
{% endhint %}

이 `PrimaryPointerInfo` 컴포넌트는 다음 속성을 가진 객체를 반환합니다:

* `screenCoordinates`: *(Vector2)* 픽셀 단위로 표현된 씬 내 커서 위치입니다. 원점은 화면의 왼쪽 상단 모서리이며, `y` 아래 방향으로 증가합니다 — 다음과 같은 좌표 공간입니다 `UiTransform` 과 `UiCanvasInformation`. 커서가 잠겨 있으면 화면 중앙을 보고합니다.
* `screenDelta`: *(Vector2)* 이전 프레임 이후 커서 위치의 변화량으로, 픽셀 단위입니다. 자세한 내용과 예제는 다음을 참조하세요 [마우스 이동](/creator/content-creator-ko/sdk7/interactivity/mouse-movement.md) 자세한 내용과 예제는.
* `worldRayDirection`: *(Vector3)* 카메라에서 커서로 향하는 광선의 방향을 나타내는 벡터입니다. 원점은 카메라 위치입니다. 이를 사용해 월드에서 커서의 위치를 계산하세요.
* `pointerType`: 0은 `none`, 1은 `마우스`

{% hint style="info" %}
**💡 팁**: 다른 속성과 달리, `screenDelta` 커서가 [잠겨 있어도 마우스 움직임을 계속 보고합니다.](/creator/content-creator-ko/sdk7/interactivity/button-events/click-events.md#lock-or-unlock-the-cursor)따라서 드래그 제스처나 사용자 지정 카메라 제어 같은 실시간 상호작용에 이상적입니다. 다음을 참조하세요 [마우스 이동](/creator/content-creator-ko/sdk7/interactivity/mouse-movement.md).
{% endhint %}

{% hint style="info" %}
**팁:** UI 요소의 단순 호버 이벤트에 반응하려면 다음을 사용하는 것이 더 쉬울 수 있습니다 `onMouseEnter` 과 `onMouseLeave` 이벤트를 참조하세요 [UI 버튼 이벤트](/creator/content-creator-ko/sdk7/2d-ui/ui_button_events.md#hover-feedback).
{% endhint %}

이 `PrimaryPointerInfo` 컴포넌트는 읽기 전용이므로 플레이어의 커서 위치를 강제로 변경할 수 없습니다.

다음 예제는 UI 요소에 커서 위치를 표시하는 방법을 보여줍니다.

***ui.tsx 파일:***

```tsx
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'
import {cursorXpos, cursorYpos} from './index'

export const uiMenu = () => (
  <UiEntity
    uiTransform={{
			width: '100%',
			height: '100px',
			justifyContent: 'center',
			alignItems: 'center',
    }}
    uiText={{ value: `Cursor pos: `+  cursorXpos + `,` + cursorYpos, fontSize: 40 }}
    uiBackground={{ color: Color4.create(0.5, 0.8, 0.1, 0.6) }}
  />
)
```

***index.ts 파일:***

```ts
import { engine, PrimaryPointerInfo } from '@dcl/sdk/ecs'
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
  ReactEcsRenderer.setUiRenderer(uiMenu)
}

export let cursorXpos: number | undefined = undefined
export let cursorYpos: number | undefined = undefined

function CursorSystem() {
  const pointerInfo = PrimaryPointerInfo.get(engine.RootEntity)
  console.log(pointerInfo)

  cursorXpos = pointerInfo.screenCoordinates?.x
  cursorYpos = pointerInfo.screenCoordinates?.y
}

engine.addSystem(CursorSystem)
```

다음을 사용할 수 있습니다 `worldRayDirection` 다음을 설정하려면 `방향` 레이캐스트의 필드가 엔티티가 커서의 시선 안에 있는지 확인합니다. 다음을 참조하세요 [레이캐스팅](/creator/content-creator-ko/sdk7/interactivity/raycasting.md) 자세한 내용은.


---

# 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/interactivity/user-data.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.
