월드 좌표와 스크린 좌표

# 학습 과정 소개

메이플스토리 월드의 월드 공간과 스크린 공간이 존재합니다. 각 공간에서는 서로 다른 좌표계를 사용합니다. 두 공간에서 사용하는 좌표계에 대해 알아봅시다.

# 월드 공간

월드 공간이란 Hierarchy - world - map의 공간을 의미합니다.

## 월드 좌표

월드 좌표는 맵에서의 특정 위치 값입니다. 맵에 배치된 엔티티의`TransformComponent.WorldPosition` 값이 월드 좌표입니다. 월드 좌표의 원점은 맵의 중앙입니다. 예를 들어 아래 이미지와 같이 분수 Entity는 월드에서 X = 23.91, Y = -3.37, Z = 999.953에 위치한다는 것을 WorldPosition 값으로 알 수 있습니다.

[png](16560451065876f02eae1080d46618432600ef68e44ec)

# 스크린 공간

스크린 공간에서 사용되는 좌표는 Screen 좌표와 UI 좌표로 나눌 수 있습니다. 두 가지 좌표 모두 화면 상의 위치 값을 말하지만, 좌표를 계산하는 방식이 다릅니다.

## Screen 좌표

Screen 좌표는 기기의 디스플레이 해상도 픽셀 수와 동일합니다. Screen 좌표의 원점은 좌측 하단이고, 기기마다 액정의 해상도가 다르므로 Screen 좌표의 최댓값 또한 다릅니다. 예를 들어 아이폰 16의 경우 최댓값은 2556 x 1179이고, 갤럭시 S25의 최댓값은 2340 x 1080입니다. Screen 좌표의 값은 `ScreenTouchEvent`, `ScreenTouchHoldEvent`, `UILogic.ScreenWidth`, `UILogic.ScreenHeight`를 활용해 확인할 수 있습니다.

아래는 Samsung Galaxy S10+의 Screen 좌표 원점과 최댓값 좌표입니다.

[png](17515098580721c29bc7c83a24474bf1b38fb72f3a236)

## UI 좌표

UI 좌표는 기기에 따라 원점과 최댓값이 달라집니다. UI 좌표의 기본 원점은 보이는 화면의 중앙이고, UI 좌표의 최댓값은 1920 x 1080에 가깝게 맞춰집니다.

#### 기기별 UI 좌표 원점

  * PC: 보이는 캔버스의 중앙이 원점(0,0)입니다. [png](1751510074818eedf66599ea54950bd381b1b30a3f6bf)
  * Mobile: Safe Area의 중앙이 원점(0,0)입니다. Safe Area란 모바일 기기에서 노치, 탭 막대 등에 영향을 받지 않고 안전하게 사용할 수 영역을 의미합니다. [png](17515100532491f1477f2f58c44f088db81ab0ca34efe)



UI를 UIGroup에 배치하면 UI 엔티티는 UI 좌표를 사용하게 됩니다. UI 좌표의 원점과 최댓값은 기기마다 다르므로 PC에서 꽉차게 배치했을지라도 다른 기기에서는 화면을 다 채우지 못할 수도 있습니다.

[{"index":"PC","0":"[png](17514482389113061b375c5af442cbc1af9c27e6f984e)"},{"index":"Apple iPhone 12 Mini","0":"[png](1751448252201c407bce361bb4d198816856516c7a183)"},{"index":"Samsung Galaxy S10+","0":"[png](1751448268722abd9bdd5be9b4e99839a6ded171432d5)"}]

# 해상도별 UI 좌표 영역 처리 방식

UI 좌표 영역의 기본 해상도는 1920 x 1080, 기본 비율은 16:9입니다. 기기 해상도에 따라 월드 화면이 확대/축소되어도 해상도에 관련 없이 항상 눈에 보이는 화면은 모습은 동일하게 유지되도록 처리됩니다.

#### PC

PC를 사용하는 메이플스토리 월드 유저는 창 크기를 변경할 수 있습니다. 그러나 창 크기를 변경해도 창의 화면 비율은 16:9로 유지됩니다. 비율이 유지되므로 화면의 보이는 영역이 비율에 비례해 확대/축소됩니다. 단, 창이 전체 화면인 경우 모니터의 화면 비율에 따라 가로 영역이 더 많이 보이거나 더 적게 보이게 됩니다. 예를 들어 창 크기가 1920x1080일 때와 3840x2160일 때 모두 화면은 동일하게 보입니다.

[{"index":"1920x1080","0":"[png](1751526293382a3747cbf4fa24976b52d4dc05e854b79)"},{"index":"3840x2160","0":"[png](1760355323385269cedca02f343a6ad9089315fa4c96d)"}]

#### Mobile

Mobile 기기에서 월드에 입장했을 때는 화면이 가로로 변경됩니다.

보이는 영역은 16:9 비율을 기준으로 세로 영역은 동일하게, 가로 영역은 기기의 해상도 비율에 따라 더 많이 보이거나 더 적게 보여집니다. 아래 그림과 같이 16:12 비율인 iPad Pro 12.9의 해상도는 2732 x 2048이지만, 좌표 영역 전체를 계산하면 1920 x 1439입니다. Screen 좌표와 비율 차이는 약 1.42배로, 16:9에 비해 16:12 비율은 세로가 더 긴 화면이기 때문에 1920을 기준으로 캔버스 크기를 조정한 결과입니다.

[png](1751526324699a520b57239974b27a5a253474d4f7549)

또 다른 예로 19:9 비율인 갤럭시 S10+의 해상도는 3040 x 1440이지만, 캔버스 전체 크기는 2280 x 1080 입니다. 스크린 좌표와 비율 차이는 약 1.3배로, 16:9에 비해 19:9 비율은 가로가 더 긴 비율이므로 1080을 기준으로 캔버스 크기를 조정한 결과입니다.

[png](1751526357807622abec3694e4ac9a02bc427a92e8ad9)

# UI 좌표 설정

UI는 `UITransformComponent`의 Anchor Presets 설정을 기준으로 PosX, PosY 값만큼 떨어진 곳에 배치됩니다. Anchor Presets 설정에 따라 필요한 Property가 달라집니다.

[png](1754011712034b9838df4d63c4911a492903c6d88962f)

#### Anchor 설정

Anchor는 `UITransformComponent`의 격자 무늬 아이콘을 눌러 선택할 수 있습니다. 선택한 후 PosX와 PosY를 입력하면 Anchor를 기준으로 입력한 값만큼 떨어진 위치에 UI가 배치됩니다. 이때 UI 앵커의 기준점은 Safe Area 영역입니다.

[png](1652754058498d1bc17b4c1d04e75bc8000fde8722de1)

Anchor를 형태(Stretch)로 설정하면 UI가 설정에 맞게 늘어납니다. Anchor가 길게 늘어나는 경우, 종류에 따라 설정할 수 있는 프로퍼티가 달라집니다. 예를 들어, 팝업 메시지의 검은색 반투명 배경 이미지(PopupBack)는 정중앙을 기준으로 UI가 사방으로 늘어 화면을 덮도록 설정되어 있습니다. 어떤 해상도에서든 팝업 메시지가 떴을 때 검은색 배경 이미지가 화려한 색상의 맵을 덮어주어 유저가 팝업 메시지에만 집중하도록 합니다. [png](165604560743653ab60032b284c4cb1fa149610be2b93)

#### Anchor Presets 종류

[{"Anchor":"[png](1652753675728c2aaf37b9f124af7893d195adcef175b)","설명":"상단 왼쪽 끝을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](165275370174172181339e3834ca086504f0c535151ff)","설명":"상단 중앙을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](1652753728860c87e3a1bb08b4b5580456a8cce00f406)","설명":"상단 오른쪽 끝을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](16527537526160827153fdd254b85883a0b2034f68230)","설명":"중앙 왼쪽 끝을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](1652753775316eb1fa9ba8c1b45b29705a7728b78db74)","설명":"정중앙을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](1652753795158b1e8a296bbf44fddb88e77f0d9dd67bf)","설명":"중앙 오른쪽 끝을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](165275381909396f89e4e066c4a9392fb67db882319e1)","설명":"하단 왼쪽 끝을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](16527538405956b6dc7cc784f492cad18daaf2f449f22)","설명":"하단 중앙을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](1652753858060d23fdebc0f4b4f9293594b55d52eacb1)","설명":"하단 오른쪽 끝을 기준으로 PosX, PosY 만큼 떨어진 곳에 UI가 위치합니다."},{"Anchor":"[png](165276280240576b4802818d74cf095e74237cb57da69)","설명":"상단 중앙을 기준으로 Left, Right 값만큼 남기고 UI가 가로로 늘어납니다. 상단 중앙을 기준으로 PosY 값만큼 떨어진 곳에 위치합니다."},{"Anchor":"[png](165276284856863a5c32a8f6c4e20b6261d44d2bda729)","설명":"정중앙을 기준으로 Left, Right 값만큼 남기고 UI가 가로로 늘어납니다. 정중앙을 기준으로 PosY 값만큼 떨어진 곳에 위치합니다."},{"Anchor":"[png](16527628656822017ed5fcffc4ed7ac43bc57234b13f8)","설명":"하단 중앙을 기준으로 Left, Right 값만큼 남기고 UI가 가로로 늘어납니다. 하단 중앙을 기준으로 PosY 값만큼 떨어진 곳에 위치합니다."},{"Anchor":"[png](165276288320119af691b47d54ee5a5f8f8cc841ba772)","설명":"왼쪽 중앙을 기준으로 Top, Bottom 값만큼 남기고 UI가 세로로 늘어납니다. 왼쪽 중앙을 기준으로 PosX 값만큼 떨어진 곳에 위치합니다."},{"Anchor":"[png](1652762899845dbdb414c754049a5b95a6e0d3f7426b8)","설명":"정중앙을 기준으로 Top, Bottom 값만큼 남기고 UI가 세로로 늘어납니다. 정중앙을 기준으로 PosX 값만큼 떨어진 곳에 위치합니다."},{"Anchor":"[png](1652762937587653a13ae666f45329c6afa9c618617e4)","설명":"오른쪽 중앙을 기준으로 Top, Bottom 값만큼 남기고 UI가 세로로 늘어납니다. 오른쪽 중앙을 기준으로 PosX 값만큼 떨어진 곳에 위치합니다."},{"Anchor":"[png](1652762962358809eb3ba031f47f491b2a12900b0b324)","설명":"정중앙을 기준으로 Left, Right, Top, Bottom 값만큼 남기고 UI가 사방으로 늘어납니다."}]

# Anchor Presets 활용

기기마다 해상도와 Safe Area가 다르므로 UI 좌표로 UI 위치를 결정할 경우 기기에 따라 UI의 일부가 잘려 보이거나, 보이지 않을 수 있습니다. 모든 기기의 Safe Area를 확인해 UI 위치를 일일이 지정하는 것은 효율적인 제작 방식이 아니므로 UI의 특정 지점을 기준으로 얼마나 떨어져 있을 것인지와 같은 다른 기준으로 UI를 배치해야 합니다.

UI 좌표에 맞추어 UI를 배치했을 발생하는 문제를 살펴봅시다. UI는 스크린 해상도의 변화에 따라 위치가 달라지게 됩니다. 크리에이터가 버튼 하나를 Anchor를 정중앙으로 설정하고, 화면 우측 소셜 버튼 아래에 배치하려 한다고 생각해 봅시다. 크리에이터는 UI 좌표 800, 400 위치에 버튼을 배치했습니다. 1920 X 1084(16:9) 해상도의 스크린에서 월드를 플레이할 경우 크리에이터가 원하는 위치에 보입니다.

[png](1761722356633567344378b9c4005b5c0d3ded1e480f8)

3040 X 1440(19:9) 해상도의 스크린으로 월드를 플레이할 경우 크리에이터가 의도하지 않은 곳에 UI 버튼이 위치하게 됩니다. 스크린 해상도의 비율이 다르기 때문입니다. 유저 디바이스 해상도가 어떻든 크리에이터가 원하는 곳에 UI 요소를 보여주려면 Anchor Presets 기능을 활용해야 합니다.

[png](17617232008259055a237bce9451fb3ea92694455b9cd)

이처럼 다양한 해상도에 대응하기 위해 `UITransformComponent`에서 Anchor를 설정해 UI의 거리를 계산할 수 있습니다. Anchor는 원점으로부터 PosX, PosY 값만큼 떨어진 곳에 배치됩니다. 예를 들어 메이플스토리 월드에서 제공하는 기본 채팅 UI는 Anchor Point가 좌상단 끝으로 설정되어 있습니다. 이렇게 설정되어 있다면 채팅 UI는 어떤 기기든 좌상단 끝을 기준으로 368.9725, -251.8051 만큼 떨어진 곳에 위치하게 됩니다.

[png](165604514596759c47da1127745c2b9207457e3d9bbe9)

# UI 좌표와 Screen 좌표 차이

UI 좌표와 Screen 좌표는 비율과 원점의 위치가 다르기 때문에 같은 위치에서도 다른 좌표값을 가지고 있습니다. 그러므로 Screen 좌표값을 `UITransformComponent.Position` 값에 그대로 넣어 사용할 경우 예상하는 위치와 다른 곳에 UI 엔티티가 위치하게 됩니다. 모바일의 경우 기기의 화면 비율을 반영해 UI 좌표의 최댓값이 결정됩니다.

Galaxy S10+로 시뮬레이터를 설정해두고 UI TransformComponent의 Anchor Preset을 이용해 봅시다. UI 엔티티를 생성하고, UITransformComponent - Anchor Preset을 사방 스트레치를 선택해 Left, Right, Top, Bottom값을 모두 0으로 만들어 화면 전체를 덮도록 만들어봅시다. 화면을 덮도록 만들었지만, Safe Area 영역만 채워지는 것을 확인할 수 있습니다. 덮어진 Saf Area의 UI 좌표 값은 2173.5 x 1080이고, 원점은 Safe Area의 중앙입니다. 그러나 Screen 좌표에서는 `UILogic.ScreenWidth`은 3040 , `UILogic.ScreenHeight` 1440이고, 이 좌표는 Screen 좌표이므로 원점이 좌측 하단입니다.

[png](1751526243746915bec31023144ad83bb3513bbee6799)