> 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)
	console.log('플레이어 회전: ', playerRot)
	console.log('카메라 위치: ', CameraPos)
	console.log('카메라 회전: ', CameraRot)
}

engine.addSystem(getPlayerPosition)
```

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

{% hint style="warning" %}
**📔 참고**: 초기 씬 로딩 시에는 `engine.PlayerEntity` 또는 `engine.CameraEntity` 초기 씬 로딩 중에는, 엔티티가 아직 초기화되지 않았을 경우 오류가 발생할 수 있기 때문에 이 시점에서 사용하지 마세요. 이 문제를 피하려면, 이것들을 `함수 내부,` 함수 안에서 사용하거나, 간접적으로 호출되는 함수 안에서 사용하세요. `함수 내부,`. 동작을 비동기 [`executeTask` block](/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('플레이어 데이터: ', { 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`: *(string)* 다른 사람들이 월드 안에서 보는 플레이어의 사용자 이름
* `userId`: *(string)* 플레이어를 식별하는 문자열입니다. 지갑으로 연결된 플레이어의 경우, 지갑 주소를 소문자로 쓴 값입니다. 게스트 계정의 경우에는 로컬에서 생성된 식별자입니다.
* `isGuest`: *(boolean)* 플레이어에게 공개 키가 있는지 나타냅니다. *참* 공개 키가 없는 게스트 계정인 경우입니다.
* `위치`: *(Vector3)* 씬에서 아바타의 위치입니다.
* `아바타`: 플레이어의 기본 아바타와 외형에 대한 데이터를 담고 있는 중첩 객체입니다.
* `wearables`: 플레이어가 현재 착용 중인 각 웨어러블의 식별자 배열입니다. 예를 들어 `urn:decentraland:off-chain:base-avatars:green_hoodie`. 모든 웨어러블은 NFT인지 여부와 상관없이 비슷한 식별자를 가집니다.
* `emotes`: 플레이어가 빠른 접근 휠에 현재 장착한 각 이모트의 식별자 배열입니다.
* `entity`: 플레이어 엔티티에 대한 참조입니다. 다른 함수에 전달하거나 여기에 커스텀 컴포넌트를 추가할 때 유용할 수 있습니다.

그 `아바타` 객체에는 다음과 같은 중첩 정보가 있습니다:

* `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()` 같은 씬 안에 현재 서 있는 플레이어에게서만 데이터를 가져올 수 있습니다. 반드시 시각적 범위 안에 있을 필요는 없지만, 같은 통신 섬에 연결되어 있어야 합니다. 미리보기에서 이것을 시험해 보려면, 두 번째 탭을 열어 다른 계정으로 로그인한 뒤 두 플레이어가 모두 씬 안에 서 있게 하세요.

{% 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`: *(string)* 다른 사람들이 월드 안에서 보는 플레이어의 사용자 이름
* `userId`: *(string)* 플레이어를 식별하는 UUID 문자열입니다. 플레이어에게 공개 키가 있으면, 이 필드는 공개 키와 같은 값을 가집니다.
* `hasConnectedWeb3`: *(boolean)* 플레이어에게 공개 키가 있는지 나타냅니다. *참* 플레이어가 하나를 가지고 있는 경우입니다.
* `publicKey`: *(string)* 플레이어의 이더리움 지갑 공개 키입니다. 플레이어가 연결된 지갑 없이 게스트로 로그인하면, 이 필드는 `null`.
* `아바타`: 플레이어 외형 데이터가 들어 있는 중첩 객체입니다.
* `version`: *(number)* 플레이어가 설정을 변경할 때마다 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 %}

## 포터블 경험 가져오기

포터블 경험은 본질적으로 토지 구획에 제한되지 않는 씬입니다. 플레이어는 어디를 가든 이것들을 가지고 다닐 수 있으며, 월드 위에 새로운 콘텐츠 계층을 추가합니다. 스마트 웨어러블은 포터블 경험의 예입니다. 경쟁 게임에서 부정행위로 간주될 수 있는 능력을 플레이어에게 제공할 수 있는 스마트 웨어러블을 착용했는지 알고 싶을 수 있습니다. 예를 들어 플랫폼 게임에서 제트팩을 착용한 플레이어는 다른 플레이어보다 매우 불공정한 이점을 가집니다.

씬 제작자로서, 포터블 경험을 착용한 플레이어가 씬에서 할 수 있는 일을 제한하고 싶을 수 있습니다. `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) 로 요청하여, 현재 사용 가능한 모든 웨어러블의 전체 최신 목록과 각 웨어러블의 세부 정보를 얻으세요.

`${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에서 가져올 수 있습니다](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) {
		console.log('플레이어가 3인칭 카메라를 사용 중입니다')
	} else {
		console.log('플레이어가 1인칭 카메라를 사용 중입니다')
	}
}

engine.addSystem(checkCameraMode)
```

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

카메라 모드는 `CameraType` 열거형의 값을 사용합니다. 다음 값이 가능합니다:

* `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` 초기 씬 로딩 중에는, 엔티티가 아직 초기화되지 않았을 경우 오류가 발생할 수 있기 때문에 이 시점에서 사용하지 마세요. 이 문제를 피하려면, 이것들을 `함수 내부,` 함수 안에서 사용하거나, 간접적으로 호출되는 함수 안에서 사용하세요. `함수 내부,`. 동작을 비동기 [`executeTask` block](/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` 초기 씬 로딩 중에는, 엔티티가 아직 초기화되지 않았을 경우 오류가 발생할 수 있기 때문에 이 시점에서 사용하지 마세요. 이 문제를 피하려면, 이것들을 `함수 내부,` 함수 안에서 사용하거나, 간접적으로 호출되는 함수 안에서 사용하세요. `함수 내부,`. 동작을 비동기 [`executeTask` block](/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)* 씬에서 커서의 위치로, 픽셀 단위로 표현됩니다. 원점은 화면의 왼쪽 아래 모서리입니다. 커서가 잠겨 있으면 화면 중앙을 보고합니다.
* `screenDelta`: *(Vector2)* 이전 프레임 이후 커서 위치의 변화로, 픽셀 단위로 표현됩니다. 자세한 내용과 예시는 [마우스 이동](/creator/content-creator-ko/sdk7/interactivity/mouse-movement.md) 를 참조하세요.
* `worldRayDirection`: *(Vector3)* 카메라에서 커서로 향하는 광선의 방향을 나타내는 벡터입니다. 원점은 카메라 위치입니다. 이를 사용해 월드에서 커서의 위치를 계산하세요.
* `pointerType`: `none`은 `마우스`

{% 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: `커서 위치: `+  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 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/user-data.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.
