For the complete documentation index, see llms.txt. This page is also available as Markdown.

화면 UI

씬에서 플레이어를 위한 UI를 만드는 방법을 알아보세요. 예를 들어 게임 관련 정보를 표시하는 데 유용합니다.

씬을 위한 UI를 만들 수 있으며, 3D 월드 공간이 아니라 화면의 고정된 2D 공간에 표시됩니다.

UI 요소는 플레이어가 씬의 LAND 구역 안에 서 있을 때만 보입니다. 인접한 씬이 자체 UI를 표시할 수도 있기 때문입니다. UI의 일부는 월드 공간에서 특정 이벤트가 발생할 때 열리도록 트리거할 수도 있습니다. 예를 들어 플레이어가 특정 지점을 클릭하는 경우입니다.

중첩된 구조를 정의하여 UI를 만듭니다 UiEntity 객체를 JSX로 정의합니다. UI에 사용되는 문법은 다음과 매우 유사합니다 React (웹 UI를 만들기 위한 매우 인기 있는 JavaScript 기반 라이브러리입니다).

정적인 요소로만 이루어진 간단한 UI는 HTML과 매우 비슷해 보일 수 있지만, 상태 변화에 반응하는 동적 요소를 추가하면 훨씬 더 강력한 작업을 할 수 있습니다.

기본 Decentraland 익스플로러 UI에는 채팅 위젯, 지도, 기타 요소가 포함됩니다. 이러한 UI 요소는 항상 최상위 레이어에 표시되며, 씬별 UI보다 위에 있습니다. 따라서 씬에 이들과 같은 화면 공간을 차지하는 UI 요소가 있으면 가려집니다.

참조 UX 가이드라인 UI의 모양과 느낌을 설계하는 방법에 대한 팁은

📱 모바일용 디자인: 기기는 노치, 상태 표시줄, 홈 인디케이터 및 둥근 모서리를 위해 화면 공간을 예약하며, 클라이언트는 캔버스의 일부 위에 자체 컨트롤을 그립니다. 둘 다 직접 측정하지는 마세요 — 아래의 screenInset 으로 UI가 배치될 영역을 선택하세요. 기본적으로 기기 안전 영역이 사용되므로, 별도 작업 없이 하드웨어 여백이 피됩니다. 게시하기 전에 다음을 검토하세요 모바일 안전 영역 및 모바일용 UI 모범 사례.

플레이어가 아래의 UI 닫기 버튼을 화면 오른쪽 아래에서 클릭하면 모든 UI 요소가 숨겨집니다.

UI 렌더링하기

씬에 UI를 표시하려면 ReactEcsRenderer.setUiRenderer() 함수를 사용하고, 다음에 설명된 유효한 엔티티 구조를 전달하세요 .tsx 파일.

각 엔티티는 HTML과 유사한 노드로 정의되며, 각 컴포넌트에 대한 속성을 가집니다.

ui.tsx 파일:

import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
  <UiEntity
    uiTransform={{
      width: 700,
      height: 400,
      margin: { top: '35px', left: '500px' },
    }}
    uiBackground={{ color: Color4.Red() }}
  />
)

index.ts 파일:

엔티티 구조를 정의하고 렌더링하는 작업을 하나의 명령으로도 할 수 있습니다 .tsx 파일.

ui.tsx 파일:

index.ts 파일:

UI 엔티티

UI의 각 요소는 별도의 UiEntity로 정의되어야 하며, 이미지, 텍스트, 배경, 보이지 않는 정렬 박스 등 어떤 것이든 가능합니다. 씬의 3D 공간과 마찬가지로 각 UiEntity 은 위치, 색상 등을 부여하는 자체 컴포넌트를 가집니다.

React와 유사한 문법을 사용하면 각 컴포넌트를 UiEntity내의 속성으로 지정할 수 있어 코드가 더 짧고 읽기 쉬워집니다.

에서 사용되는 컴포넌트는 UiEntity 일반 엔티티에서 사용되는 것과 다릅니다. UI 컴포넌트를 일반 엔티티에 적용할 수도 없고, 일반 컴포넌트를 UI 엔티티에 적용할 수도 없습니다.

다음 컴포넌트를 UiEntity:

  • uiTransform

  • uiBackground

  • uiText

  • onMouseDown

  • onMouseUp

  • onMouseEnter

  • onMouseLeave

  • uiInputBinding — 요소가 눌려 있는 동안 입력 동작을 유지하여 사용자 지정 컨트롤을 만듭니다

HTML 태그처럼, 컴포넌트를 자기 자신만 닫는 형태로 정의하거나 하나를 다른 것 안에 중첩할 수 있습니다.

ui.tsx 파일:

index.ts 파일:

UI 모듈의 정의에는 부모 레벨 엔티티가 하나만 있을 수 있습니다. 원하는 만큼 다른 엔티티를 정의할 수 있지만, 모두 최상단에 단 하나의 부모를 가진 구조 안에 들어가야 합니다.

화면 가상 스케일

UI의 가상 너비와 높이를 설정하세요. 이렇게 하면 실제 픽셀 화면 크기와 상관없이 다양한 화면 크기에서 UI가 동일하게 보입니다.

가상 너비를 1920, 가상 높이를 1080으로 설정하면 UI는 화면 크기에 맞게 스케일됩니다. 화면이 1920x1080이면 UI는 가상 크기와 같은 크기로 표시됩니다. 화면이 더 크거나 작으면 픽셀 값은 모두 가상 크기에 맞도록 스케일됩니다. 예를 들어 화면이 3840x2160이라면 너비가 100픽셀로 정의된 항목은 실제 200픽셀로 표시됩니다.

픽셀 값에 곱해지는 UI 스케일 팩터의 실제 계산식은 Math.min(realWidth / virtualWidth, realHeight / virtualHeight).

기본 가상 크기

가상 크기는 선택 사항이지만 두 차원은 함께 사용해야 합니다: 둘 다 전달하거나 둘 다 전달하지 않아야 합니다. 하나도 전달하지 않으면 플랫폼 기본값이 적용됩니다:

플랫폼
기본 가상 크기

모바일

1600x720

데스크톱 및 웹

1920x1080

즉, 옵션을 전혀 전달하지 않아도 UI의 픽셀 값은 항상 기준 해상도에 대해 스케일됩니다. 이는 씬이 다음만 사용하는 경우에도 적용됩니다 addUiRenderer() 를 호출하지 않고 setUiRenderer().

세 가지 특별한 경우:

  • 스케일링 제외하기: 유효하지 않은 크기 — 0 이하인 값이라면 무엇이든 사용하세요 — 를 전달하면 가상 화면이 완전히 비활성화됩니다. 그러면 픽셀 값은 스케일링 없이 원시 캔버스 픽셀로 사용됩니다. 이것이 가상 화면을 끄는 문서화된 방법이므로 아무 것도 기록되지 않습니다.

  • 불완전한 크기: 두 차원 중 하나만 전달하는 것도 유효하지 않으며, 위의 경우와 마찬가지로 가상 화면이 비활성화됩니다. 플랫폼 기본값이 적용되지 않습니다. 위의 제외 사례와 달리 이것은 보고됩니다. 절반만 전달된 크기는 의도적인 선택이 아니라 실수이므로 SDK가 다음을 기록합니다 불완전한 가상 화면 크기(…): 두 차원이 모두 필요하므로 가상 화면이 비활성화되고 UI 스케일링이 적용되지 않습니다. 각 크기당 한 번. 두 차원을 모두 전달하거나, 둘 다 전달하지 마세요.

    주 렌더러에서는 꼭 다시 확인할 가치가 있습니다. 거기서 불완전한 크기도 씬 전체의 전환이기 때문입니다. setUiRenderer() 라고 언급하는 어느 한 차원이든 addUiRenderer()보다 우선합니다. 따라서 위의 예시는 씬 전체에 대해 가상 화면을 비활성화하고, 추가 렌더러에 전달된 유효한 크기를 무시합니다.

  • 모바일의 16:9 크기: 휴대폰 화면은 16:9보다 훨씬 넓기 때문에 16:9 가상 캔버스는 UI에 레터박스를 넣게 됩니다. 16:9 크기(1920x1080, 1280x720, …)를 전달하고 씬이 모바일에서 실행되면, 이는 1600x720로 재정의되며, 콘솔에 한 번 메시지가 기록됩니다. 모바일에서 16:9가 아닌 크기와 데스크톱 또는 웹에서의 모든 유효한 크기는 그대로 적용됩니다.

📔 참고: vw 그리고 vh 단위는 가상 화면과 독립적입니다: 1vw 는 캔버스 너비의 1%이고 1vh 는 캔버스 높이의 1%이며, CSS와 정확히 같습니다. 또한 screenInset를 무시하므로 기본 'device' 내부에서는 width: '100vw' 가 width: '100%' 보다 더 넓습니다 — 첫 번째는 화면 전체를 차지하고, 두 번째는 인셋 영역을 채웁니다.

📱 참고: 플랫폼 감지는 비동기적으로 해결됩니다. 첫 몇 프레임 동안 SDK는 아직 모바일에서 실행 중인지 알지 못하므로 가상 화면은 1920x1080 에서 시작했다가 1600x720 로 전환됩니다

화면 인셋 영역

화면은 완전히 사용할 수 있는 상태가 아닙니다: 휴대폰은 노치, 상태 표시줄, 홈 인디케이터 및 둥근 모서리를 위해 공간을 예약하고, 모든 익스플로러는 캔버스 일부 위에 자체 HUD(미니맵, 채팅, …)를 그립니다. 렌더러 옵션의 선택적 screenInset 속성은 UI가 배치될 화면 영역을 선택합니다:

값
UI가 배치되는 영역

'device' (기본값)

노치, 상태 표시줄 및 둥근 모서리를 제외한 기기 안전 영역입니다. 다음에서 읽습니다 UiCanvasInformation.screenInsetArea.

'interactable'

익스플로러가 자체 HUD(미니맵, 채팅, …)가 없는 것으로 보고하는 영역입니다. 다음에서 읽습니다 UiCanvasInformation.interactableArea. 무엇을 포함하는지는 각 익스플로러에 따라 다릅니다 — 대상 플랫폼에서 확인하세요.

'none'

전체 화면이며, 0,0 가 왼쪽 위 모서리에 있습니다.

데스크톱에서는 기기 인셋이 0이므로 'device' 그곳에서는 UI를 전체 화면에 배치합니다 — 다음과 같은 결과입니다 'none'. 영역은 매 틱마다 다시 읽히므로, 회전하거나 시스템 바가 나타났다 사라질 때처럼 인셋이 변경되면 UI도 이를 따라갑니다.

실제 기기에서의 세 가지 영역

아래 캡처는 같은 휴대폰에서 같은 씬을, 오직 screenInset 값만 바꿔 세 번 렌더링한 결과입니다. 자홍색 사각형은 UI 자체이고, 윤곽선은 익스플로러가 보고하는 영역입니다 — 청록색은 전체 캔버스, 호박색은 screenInsetArea, 녹색은 interactableArea.

Scene UI covering the whole phone screen, including the notch strip and the areas under the client controls
screenInset: 'none' — UI가 전체 캔버스를 덮습니다. 모서리는 노치 아래와 클라이언트 자체 컨트롤 뒤에 있습니다.
Scene UI inset to the device safe area, clear of the notch
screenInset: 'device' (기본값) — UI가 기기 안전 영역 안으로 들어가 노치와 둥근 모서리에서 벗어납니다. 여전히 클라이언트의 컨트롤과 겹치는데, 이는 이 영역의 일부가 아닙니다.
Scene UI inset to the area the client reports as free of its own HUD
screenInset: 'interactable' — UI가 클라이언트가 씬 UI를 위해 지정한 사각형 안에 배치됩니다. 캡처된 모바일 클라이언트 1.12.1에서는 왼쪽 열(프로필, 채팅, 조이스틱)이 제외되며, 오른쪽 아래의 액션 버튼은 설계상 해당 영역 위에 그려집니다.

💡 팁: 'interactable' 는 각 익스플로러가 씬 UI를 위해 지정하는 영역을 제공합니다. 이것은 의도적으로 "모든 클라이언트 컨트롤이 그 밖에 있다"와는 다릅니다 — 세 번째 캡처에서 보이듯 모바일 액션 버튼은 의도적으로 영역 위에 그려집니다. 그 아래에 배치한 것은 여전히 접근 가능하지만 같은 탭을 놓고 경쟁하므로, 붐비는 모서리 를 염두에 두고 대상 플랫폼에서 확인하세요: 영역이 무엇을 포함하는지는 각 익스플로러의 판단이며 버전마다 달라질 수 있습니다.

각 렌더러는 자체 screenInset를 존중하므로, 메인 UI와 addUiRenderer() 로 추가된 어떤 UI도 서로 다른 영역을 동시에 사용할 수 있습니다. 가상 크기와 달리 이 값은 렌더러 간에 공유되지 않습니다.

여러 UI 모듈

씬에 각자 UI를 정의하는 여러 시스템이나 모듈이 있다면, 각 UI 모듈을 ReactEcsRenderer.addUiRenderer()로 렌더링할 수 있습니다. 이는 여러 UI 컴포넌트를 가진 복잡한 씬을 작업할 때 특히 유용하며, 스마트 아이템를 정의할 때도 유용합니다. 이는 씬의 나머지 코드와 무관하게 사용 가능해야 합니다.

해당 ReactEcsRenderer.addUiRenderer() 함수는 UI의 소유자로 엔티티를 제공해야 합니다. 이는 어떤 엔티티든 될 수 있으며, UI의 소유자로 사용하기 위해서만 만든 더미 엔티티도 가능합니다.

이 코드 조각은 씬의 다른 UI 코드와 독립적으로 존재할 수 있습니다. 씬의 나머지 부분에는 ReactEcsRenderer.setUiRenderer()가 포함될 수도 있고 전혀 없을 수도 있지만, UI는 여전히 렌더링됩니다.

하나의 addUiRenderer() 호출도 다음과 마찬가지로 가상 너비와 높이를 포함할 수 있습니다 setUiRenderer(). 그러나 씬에 가상 너비와 높이를 정의하는 setUiRenderer() 호출도 있다면, addUiRenderer() 호출의 가상 너비와 높이는 무시됩니다.

가상 크기는 씬 전체의 단일 값이며, 다음과 같이 해결됩니다: setUiRenderer() 의 크기가 우선하고, 그렇지 않으면 처음으로 addUiRenderer() 를 호출해 하나를 제공한 쪽이 우선하며, 어떤 렌더러도 제공하지 않았다면 플랫폼 기본값 이 적용됩니다. 오직 screenInset 만 포함하는 옵션은 제공된 크기로 간주되지 않습니다.

해당 screenInset 는 반대로 동작합니다 — 렌더러별이므로 각 UI 모듈은 서로 다른 화면 영역에 배치될 수 있습니다:

그 UI는 다음으로 제거할 수 있습니다 ReactEcsRenderer.removeUiRenderer(dummyEntity) , 또한 UI를 소유한 엔티티가 파괴되면 UI도 함께 제거됩니다. 동일한 엔티티에 대해 ReactEcsRenderer.addUiRenderer() 가 다른 UiRenderer로 다시 호출되면 이전 것은 정리되고 새 것이 이를 대체하며, 스태킹 순서에서의 위치는 유지됩니다. 다시 호출하는 것은 이미 렌더링된 UI 모듈의 옵션을 변경하는 방법이기도 합니다. 예를 들어 zIndex.

UI 모듈 간 스태킹 순서

기본적으로 UI 모듈은 처음 나타나는 순서대로 쌓이며, 나중에 나타난 것이 앞에 옵니다. 같은 프레임에 처음 나타난 모듈 — 일반적으로 씬의 첫 프레임 전에 등록된 모든 것 — 은 setUiRenderer() 의 메인 UI와 함께 뒤쪽에 그려지고, 그 뒤에 추가된 순서대로 다른 모듈이 이어집니다. 이를 명시적으로 제어하려면 렌더러 옵션에 zIndex 를 전달하세요: 더 높은 zIndex 를 가진 모듈이 낮은 값을 가진 모듈보다 앞에 렌더링됩니다. 나타난 순서와 무관합니다. 값을 0 에 둔 모듈은 setUiRenderer()기본 순서를 유지합니다. 이 옵션은

이것은 다음과는 다른 설정입니다 zIndex 의 UiEntity로, 오직 UI 모듈 내부의 형제 요소만 정렬합니다. 렌더러 옵션은 전체 모듈끼리의 순서를 정하고, 각 모듈 내부의 요소는 자체 zIndex.

하나의 setUiRenderer 문을 공유하기

각 UI 모듈마다 ReactEcsRenderer.addUiRenderer() 를 호출하는 대신, 다음을 호출할 수 있습니다 ReactEcsRenderer.setUiRenderer() 서로 다른 파일에 있을 수 있는 UI 모듈 배열과 함께 한 번.

아래는 더 완전한 예시입니다:

ui.tsx 파일:

index.ts 파일:

마지막 업데이트