티스토리 뷰

유니티에서 UI를 그릴 때에는 Canvas라고 하는 컴포넌트를 사용한다.

UI를 그린다는 시점에서 당연하지만, 이를 다루는 것은 유니티의 기초라고도 할 수 있다.

다만, 이 Canvas의 특성을 생각하면 그리 간단한 기능인 것은 아니다.

그러니 한번 살펴보자.

오늘은 다소 간단할 것이다.


Canvas란?

Canvas는 '화면'에 오브젝트를 그릴 수 있도록 구성된 컴포넌트로, CanvasScaler와 함께 사용해서 '원하는 해상도에 맞춰서' 화면을 구성할 수 있다.

이 설명에서 보면 어느 정도 예측할 수 있겠지만, Canvas의 역할은 하위 오브젝트를 필드가 아닌 카메라를 기준으로 그리게 해 주는 역할 만을 하고 해상도에 맞춰서 크기를 조절하는 것은 CanvasScaler의 역할이다.

여기에 기본 Canvas에는 GraphicRaycaster 컴포넌트도 달려 있어서 기본적으로 클릭/터치를 감지할 수 있게끔 구성되어 있다.

 

canvas에는 3가지 모드가 존재하는데, 각자 용도가 다르다.

  • Screen Space - OverLay: '화면'에 UI를 그리는 모드.
    • 복수의 카메라를 쓰거나, 카메라의 크기가 제한되어 있다거나 하는 경우에도 화면을 기준으로 정상적으로 UI가 그려진다.
    • 대부분의 상황에서 UI를 그릴 때 사용되는 모드.
  • Screen Space - Camera: '카메라'에 UI를 그리는 모드.
    • 복수의 카메라를 쓰거나, 카메라의 크기가 제안되어 있다거나 하는 경우, '카메라의 화면 바깥'은 UI가 잘려서 표시된다.
    • 사용할 일이 딱히 없는 편. 반대로 '화면 분할'을 구성한다고 하면 OverLay 보다는 이 쪽이 적합할 수도 있다.
  • World Space: '필드'에 UI를 그리는 모드.
    • 필드에 배치되기 때문에 게임 상의 오브젝트 처럼 그려낼 수 있다.
    • 각도나 거리에 따른 형태 변형도 적용되기 때문에, 표지판 같은 요소를 만들 때 활용하기 좋다.

이렇게 간단하게 설명해 봤으니, 이제 본론으로 넘어가 보자.


Canvas는 다다익선인가?

유니티를 익히기 시작할 때에 Canvas를 다루다 보면 자신도 모르게 다수의 Canvas로 구성하고 있는 경우가 잦다.

프리팹을 canvas 단위로 만든다거나, UI별로 canvas를 따로 만든다거나...

실제로 이런 식으로 구성하면 게임을 개발할 때에는 편하긴 하다.

프리팹 자체가 canvas다 보니 canvas에 위치할 방법을 생각하지 않아도 되고, 이래저래 신경 쓸 부분도 적기도 하다.

하지만, 시스템 측면에서 한번 생각 해 보자.

과연, 해상도에 맞춰서 스케일링 하는 것이 가벼운 연산일까?

 

결론 부터 말하자면, 정답은 '가벼운 연산이던 아니던 추가 연산이 들어가는 시점에서 남용은 안된다'이다.

해상도에 맞춰서 스케일링 하는 연산이 가벼운가 아닌가 그 전의 이야기라는 것.

 

그렇다면 적을 수록 좋은 것인가?

자, 그렇다면 이번에는 canvas를 극렬히 적게 쓰는 것이 과연 좋은 것일까를 따져보고자 한다.

위에서는 canvas가 많으면 그에 따른 연산을 처리하기 때문에 'canvas가 너무 많은 것은 좋지 않다'고 서술했었다.

하지만, canvas는 기본적으로 내부 요소가 하나 만 바뀌어도 전체를 모두 그린다.

즉, 갱신 타이밍이 다른 UI들을 하나의 canvas에 그린다면, 그리고 그 양이 많으면 많을 수록 부하가 급격하게 증가한다는 것. 이게 쌓이면 쌓일 수록 상술한 canvas의 양에 따른 부하는 가볍게 뛰어넘을 수도 있다.

즉, canvas는 너무 적어도 안 좋다.

 

많아도 안좋고, 적어도 안좋다면 어떻게 하라는 것인가?

핵심은 '적절하게 활용하자' 인 것이다.

기본적으로 갱신 타이밍이 같은 UI들 끼리는 묶어서 관리하고, 갱신 타이밍이 다른 UI를 따로 떼서 관리한다고 생각하면 편할 것이다.

다만, 이 '갱신 타이밍'을 어떻게 잡아야 좋은가? 라는 의문점이 남는다.

플레이어와 상호작용하는 UI는 갱신 주기가 비 정기적일 것이고, 특정 UI가 언제 변화하는 지를 파악해서 작성하는 것에도 한계가 있는 법이기도 하다.

이에 대해서는 그냥 간단하게 생각하자. 'UI를 기능으로 묶어서 canvas를 형성한다'는 방식으로 생각하는 것이다.

어차피 문제가 되는 것은 '너무 퍼트려놓은 경우'와 '너무 묶어놓은 경우'이니 말이다.


몬스터의 체력바를 통한 이해

몬스터의 체력바는 몬스터를 처치하는 종류의 게임을 만든다면 반드시 거치게 되는 작업이다.

이러한 몬스터 체력바를 형성하는 방법에는 몇 가지가 있는데, 그 중 2개를 통해서 상술한 방식의 특징과 장단점을 알아보도록 하자.

  • 몬스터 객체 마다 World Space Canvas로 형성한다.
    • 객체와 UI를 연동시키기가 매우 편하다. 그냥 Inspector창에서 끼워 넣어 주면 된다.
      • 특히, 이와 관련된 버그를 신경 쓸 필요가 없다는 점에서 편한 편. 그래서 체력바 UI를 만드는 영상이나 강의를 보면 대부분 이 방법으로 설명하는 편이다.
    • 다만, '몬스터 별로 Canvas가 생겨난다'라는 어마어마한 난점이 발생한다.
      • WorldSpace도 크기 기준도 해상도라서 기본적인 표시 크기가 어마어마하게 크기 때문에 Scale을 조정하여 세팅하는 경우가 잦은데, 이 경우에도 하위 오브젝트 전체에 scale을 적용하느라 부하가 발생한다.
  • 하나의 Canvas에서 각 객체의 화면에 따른 위치를 연산하여 위치를 계속 갱신 시키면서 통합 관리한다.
    • 하나의 Canvas에서 관리하기 때문에 canvas 양에 의한 처리 부하가 거의 없다.
      • 위치 연산은 그냥 변수 할당 만 하면 되는 요소이기 때문에 그렇게 부하가 크지는 않다. 일반적으로 부하는 '오브젝트 생성 및 파괴'나 '모델링의 버텍스 수'에 의해서 발생한다는 점을 명심하자.
        [물론, 그렇다고 그 이외의 것에서 최적화를 무시해도 된다는 것은 아니다.]
      • 특히 몬스터 체력바는 어차피 매 프레임 마다 갱신되는 UI라서 갱신 시점 문제도 없어서 한 데 묶어서 손해볼 만한 것이 딱히 없기도 하다.
    • 다만, '목표 객체를 추적하는 컴포넌트'를 작성해야 하기 때문에, 이에 대한 버그가 발생할 수 있다.
      • 하지만, 객체 지향의 가장 큰 강점 중 하나가 '모듈화'인 만큼, 한 번만 작성하면 이후 부터는 압도적으로 편해진다는 점도 고려하는 것이 좋다. 특히 유사하게 '오브젝트 위에 표시되는 UI'를 한데 묶어서 코딩할 수가 있어서 한 번만 버그에 고생하면 그 이후에는 별 어려움 없이 구현 가능하다는 점에서 생각 만큼 큰 단점은 아니다.

둘 중 어느 것을 선택할 지는 본인의 자유이긴 하나, 최적화 측면에서는 후자가 더 유리한 편으로 알고 있다.

반대로, 보스 정도만 체력바가 나온다거나, 특정 상황에서만 게이지 바가 나온다거나 하는 경우에는 굳이 최적화라는 명분으로 저 수고를 들일 필요는 없는 셈이기도 하다. 버그를 확실하게 방지할 수단이라는 점도 있고 말이다.

그러니, 프로젝트의 상황에 맞춰서 선택하도록 하자.


사실, 오늘의 정리 내용은 최적화와 관련된 내용인 만큼, '정답'이 있다고 하기는 힘들다.

그러니 이번 글은 이 '최적화'에 대해서 한 번 고민해 보는 시간을 가지는 용도로 참고하도록 하자.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함