본문 바로가기

유니티

[ 유니티 ] 모바일 해상도 대응하기

[ Canvas 조절로 화면비율 설정하기  ]

1 . UI Scale Mode 정하기

[ Constant Pixel Size ]

  • UI 요소가 화면 크기에 관계없이 동일한 픽셀 크기로 유지.
  • UI 요소의 크기가 변경이 안됨
  • 해상도 크기에 상관 없이 UI 요소의 크기는 고정, 높은 해상도에서는 UI가 작게 보이는 문제가 생길 수 있음.

[ Scale With Screen Size  ]

  • 화면이 커질수록 UI 요소도 같이 커진다 .
  • 기준이 되는 해상도를 설정 , 그 것에 맞는 UI 요소를 설계하면 게임 실행시 해상도가 변해도 알아서 해상도 크기에 맞게 UI 요소의 크기도 같이 변한다.
  • 기종마다 다른 해상도에 대응이 가능하기에 모바일 환경에 이상적인 모드이다 .
  • Reference Resolution은 기준 해상도이다 . 화면해상도가 더 크다면 UI가 크게 Scale 되며 작다면 더 작게 Scale된다 .
  • Match 값이 0이라면 가로를 1이라면 세로르 왜곡하지 않는다 .

Width에 가깝다면 기존 가로값인 1080은 변하지 않는다 .
Width에 가깝다면 기존 세로값인 1920은 변하지 않는다

- 해당 값은 가로 게임이라면 Width에 맞추고 , 세로 게임이라면 Height에 맞추는게 좋다 .

- 세로 게임의 경우 UI간 세로 경계 내에 맞도록 설계된 게임 플레이 영역과 UI 요소가 있기에 세로간격 유지가 중요하다 .


[ Constant Physical Size  ]

  • 화면 크기와 해상도에 관계없이 UI 요소가 동일한 물리적인 크기로 유지된다 . ex) cm 등

2 . 스크립트로 설정하기

[ 스크립트 ]

 void Start()
{
    // Set Canvas Scaler settings
    CanvasScaler scaler = GetComponent<CanvasScaler>();
    scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
    scaler.referenceResolution = new Vector2(1080, 1920);
    scaler.matchWidthOrHeight = 1f;  // 세로 게임의 경우
}

 


 

[ 노치 스크린을 위한 Safe Area 사용  ]

1 . Safe Area에 ui 맞추기

[ Safe Area ]

- 휴대폰의 노치 디자인으로 인해 터치가 안되거나 가려지는 부분을 제외한 곳이 Safe Area이다 .

- 터치가 필요한 UI 들은 해당 Area 안에 위치해야 한다 . cf ) 앱스토어 심사 탈락 사유이기도 하다 .


2 . 스크립트로 설정하기

[ 스크립트 ]

using UnityEngine;
using UnityEngine.UI;

public class USafeArea : MonoBehaviour
{
    private RectTransform safeAreaTransform;
    private ScreenOrientation lastOrientation;

    void Start()
    {       
        safeAreaTransform = GetComponent<RectTransform>();
        //현재 기기의 방향을 저장한다 .
        lastOrientation = Screen.orientation;
        
        ApplySafeArea();
    }
    
    void Update()
    {
    	if (Screen.orientation != lastOrientation)
        {
            lastOrientation = Screen.orientation;
            ApplySafeArea();
        }
    }
	
    //SafeArea의 적용
    void ApplySafeArea()
    {
        if (safeAreaTransform == null)
            return;
		
        Rect safeArea = Screen.safeArea;
        // 캔버스의 왼쪽 최하단은 (0,0) 오른쪽 최상단은 (1,1)
        //Min은 좌측하단 . Max는 우측 상단을 의미 .
        Vector2 anchorMin = safeArea.position;
        Vector2 anchorMax = safeArea.position + safeArea.size;
        
        //앵커는 0과 1 사이의 비율이므로 나눠서 구해준다 .
        anchorMin.x /= Screen.width;
        anchorMin.y /= Screen.height;
        anchorMax.x /= Screen.width;
        anchorMax.y /= Screen.height;

        safeAreaTransform.anchorMin = anchorMin;
        safeAreaTransform.anchorMax = anchorMax;
    }
}

3 . 스크립트 이해를 위한 Rect Transform

[ Rect Transform ]

  • 앵커(Anchor) : UI 요소의 원점 위치를 정한다.
  • 피벗(Pivot) : UI 요소 내부의 기준점을 정한다.
  • 위치(Pos) : 앵커와 피벗을 기준으로 결정한 실제 좌표.

[ 앵커 ]

- 앵커는 UI 요소의 원점이 될 위치이다 . Min은 왼쪽 하단의 값 / Max는 우측 상단의 값이다 .

- 해당 앵커 좌표를 원점으로 UI의 position 값이 결정된다 .

앵커가 1.0 / 1.0인 경우 우측 상단이 원점이다 . 즉 , UI요소의 부모인 캔버스 상에서의 (1.0, 1.0)이 UI의 요소의 (PosX = 0, PosY = 0) 원점이 된다.


[ 피봇 ]

- 피봇은 UI 요소의 내부 중에서 기준점이 될 위치 .

- 이 기준점을 기준으로 위치, 크기, 회전 등등이 변경된다. 

피봇이 0,0 인경우 좌측 하단이 Scale / Rotation 의 기준이 된다 .


[ 포지션 ]

- PosX / Pos Y

- UI요소의 기준점을 앵커 좌표에 맞춘 상태가 UI의 요소의 (PosX = 0, PosY = 0) 원점이 된다. 

- 이 원점을 기준으로 한 캔버스 상에서 UI 요소의 좌표

- 피봇과 앵커에 대해서 상대적으로 결정된다 .

원점으로부터 -158 만큼 x 축으로 이동한 결과

 


[ ancor의 min - max 가 같을 때 ]

절대값 모드로 사용

  • 절대값 모드로 사용된다 .
  • 캔버스의 크기가 변하더라도 UI 요소의 PosX, PosY, Width, Height값은 고정적으로 유지된다.
  • UI 요소의 위치와 크기는 유지 됨.

 

[ ancor의 min - max 가 다를 때 ]

 

상대값 모드로 사용

- X 축이 다르기에 Width 값이 사라지고 캔버스 기준 패딩값으로 변경되었다 .

- 캔버스로부터 왼쪽으로 100만큼 오른쪽으로 0만큼 패딩이 주어졌다 .

  • 위 상태는 Min 과 Max 값이 X 값만 다른 상태이다 .
  • 수직적으론 PosY, Height는 절대값 모드이지만 , 수평적으론 Left, Right 패딩값으로 크기와 위치가 결정되는 상대값 모드이다.
  • 캔버스의 크기가 변할때 Y는 고정적이지만 X는 0 ~ 50% 비율을 유지하며 캔버스 크기에 맞게 상대적으로 크기와 위치가 변한다.

 

[ 빈 공간을 위한 LetterBox 사용  ]

1 . Letter Box 만들기

[ Letter Box UI 제작 ]

- Safe Area로 비는 부분에 Letter Box로 채워준다 .

- 세로 게임이기에 상하에 위치한다 .

Top Letter Box의 설정

 

Bottom Letter Box 설정

 

2 . 스크립트로 설정하기

[ 스크립트 ]

public class ULetterBox : MonoBehaviour
{
    enum LetterBoxDirection
    {
        Top,
        Bottom,  
    }

    RectTransform _panel;
    [SerializeField]  LetterBoxDirection _direction = LetterBoxDirection.Top;

    void Awake()
    {
        _panel = (RectTransform)transform;
        USafeArea.onChangeSafeArea.AddListener(UpdateLetterBox);
    }

    private void UpdateLetterBox(Vector2 min, Vector2 max)
    {
        if (_direction == LetterBoxDirection.Top)
            _panel.anchorMin = new Vector2(0, max.y);
        else
            _panel.anchorMax = new Vector2(1, min.y);

        _panel.sizeDelta = Vector2.zero;
        _panel.anchoredPosition = Vector2.zero;
    }
}

- USafeArea에서 결정된 SafeArea 영역을 받아서 실행할 스크립트이다 . 상 하 부분의 Letter Box를 설정한다 . 

// 위 이벤트 정의
public static UnityEvent<Vector2, Vector2> onChangeSafeArea = new UnityEvent<Vector2, Vector2>();
//Apply Area 하단에 추가
onChangeSafeArea?.Invoke(anchorMin, anchorMax);

- USafeArea에 위 스크립트를 추가한다 .

다음과 같이 해상도 대응이 완료됨을 볼 수 있다 .

 

출처

https://ansohxxn.github.io/unitydocs/canvas/

 

Unity C# > UI 캔버스

유니티 공식 매뉴얼 https://docs.unity3d.com/kr/current/Manual/UnityManual.html Scripting Overview http://www.devkorea.co.kr/reference/Documentation/ScriptReference/index.html

ansohxxn.github.io