티스토리 뷰

최근 머리를 앓게 하는 문제는 바로 Multi resolution screen support이다. 검색해보면 Designed Resolution에 대한 분석글이 몇 개 있긴 한데 만족스럽게 설명이 되어있지 않았기도 하고, 생각을 정리할 필요도 있을 것 같아 포스팅을 결심하게 되었다.


모바일 세상은 굉장히 다양한 해상도가 공존하는 세상인데, 멋진 게임이라면 스케일링을 깔끔하게 해서 해상도가 달라도, 또 종횡비가 달라도 예쁘게 보여져야 하는게 인지상정이다. 문제는 내가 초보라서 그런지, 문제 해결 방법이 쉽게 떠오르지 않는다는 것이다!! 게다가 이 문제가 가장 크게 대두되는 부분이 바로 UI 배치이다. 


게임에서 UI는 유저한테 첫번째로 보이는 부분이기 때문에 굉장히 중요하다. (너무 당연한거라서 말하고도 뻘쭘하다.) 잘 만든 게임들을 보면 해상도가 달라도, 종횡비가 달라도 UI가 예쁘게 나오는 것을 확인할 수 있다. (대표적인 예로 Clash of clans)


열심히 검색을 해본 결과, 가장 많이 쓰이는 방식이 Designed Resolution을 정해놓고 개발을 진행하는 것임을 알 수 있었다. Designed Resolution 방식이란 특정한 해상도를 기준으로 개발을 하고, 실제 기기의 해상도가 다를 경우 Content scale factor라는 것과 Resource search path를 이용하여 적절하게 표현될 수 있도록 하는 것을 뜻한다. 


가장 쉽게 다중 해상도 지원을 하는 방법은 특정 사이즈로 GL View를 생성한 다음, 모바일 기기의 해상도만큼 강제로 Stretch(리사이징)해버리는 방법이다. 근데 이 방법은 여러가지 문제점이 있는데 대표적인 두 가지를 설명해보겠다.

첫 번째로 종횡비가 다른 해상도일 경우 가로 또는 세로 방향으로 좀 더 많이 리사이징 되면서 보기 흉한 모습이 연출되고 만다. 이 현상을 피하기 위해 흔히 말하는 '레터 박스'를 상하 또는 좌우에 위치시키는 방법이 제시되기도 했었다. 다만 이렇게 했을 때 역시 보기 좋은 모습은 아니다.

두 번째로 더 높은 해상도로 리사이징 됬을 때 리소스의 품질이 저하되어 보인다는 문제가 있다. 아이폰3GS 시절 해상도는 480*320만 지원하면 됬었다. 이 해상도에서 50*50 크기의 리소스를 출력하면 전혀 문제가 안된다. 그런데 레티나 디스플레이가 나오면서, 960*640 크기의 해상도에서 게임이 연출되어야 하는 상황이 발생했다. 위에서 언급한 방법대로라면 50*50 크기의 리소스를 2배로 스케일링하면 된다. 문제는 이렇게 될 경우 작은 해상도의 리소스를 확대했기 때문에 그림이 깨져서 예쁘게 보이지 않게 된다. 만약 예쁜 캐릭터가 중요한 게임인데, 캐릭터 리소스가 깨진다면 경쟁력이 약화되는 것이다.


이 문제를 해결하기 위해 앞에서 언급한 Content scale factor와 Resource search path를 이용하는 것이다. 먼저 Content scale factor를 계산해야 한다. 가로 기준으로 할 것인지, 세로 기준으로 할 것인지에 따라 다른데, 보통은 세로 기준으로 하는 것 같다. Designed Resolution이 480 * 320이었는데 현재 게임을 실행한 기기의 해상도가 960 * 640라고 생각해보자. 이 때 Content scale factor는 2이다. 480 * 320에서는 10 픽셀을 움직이던 것이 960 * 640에서는 20 픽셀을 움직여야 플레이어가 봤을 때 같은 거리를 이동한 것으로 보일 것이다. 왜냐하면 같은 크기의 화면에 밀도가 두배이기 때문이다! 대충 이러한 연유로 Content scale factor를 이용하게 된다. Cocos2d-x에서는 이 문제 해결을 위해 API를 제공해준다. CCEGLViewProtocol 클래스의 setDesignResolutionSize라는 함수인데, 이 함수를 이용하여 Designed Resolution를 정해주면 내부적으로 우리가 평범하게 사용하던 content size나 position 따위에다가 Content scale factor를 계산해준다. 문제는 내가 Content scale factor를 곱하거나 나눠줘야 하는 때가 있는데, 어떤 때에 그런 짓을 해줘야 하는지 명확하지 않다는 것이다. 이것은 나도 좀 더 연구를 해봐야 하는 부분이라 차차 정리해보려고 한다. 


그렇다면 Resource search path는 무슨 용도로 쓰이는가? 앞에서 말한 리소스 크기의 스케일링과 관련한 해결책이다. '-hd' 또는 '@2x'라는 suffix(꼬리말)가 붙은 그림파일이나 hd 폴더와 같은 것을 본 적이 있을 것이다. 이것이 바로 Resource search path인데, 한 마디로 Designed Resolution과 다른 해상도이면 더 큰 이미지 혹은 작은 이미지를 불러와서 스케일링을 하지 않게 함으로써 품질 저하가 일어나지 않게 한다는 것이다. Designed Resolution이 480 * 320일 때 960 * 640 해상도에서 50 * 50 그림 파일을 불러와서 2배 스케일링을 하던 것에서, 특정 폴더에 있는 '원래 2배 크기로 만들어져 있는 이미지'를 스케일링 하지 않은채 띄워주는 것이다. 그 결과 원래 리소스의 품질 그대로 연출할 수 있게 된다.


굉장히 길게 설명했는데, 이 부분에 대해서는 샘플로 주어지는 HelloCpp와 같은 프로젝트를 참고하면 된다. Resource search path를 넣는 것과 Designed Resolution을 설정하는 것이 AppDelegate.cpp에 잘 나와있다.




이 쯤 되면 제목에 왜 CocoStudio가 언급되어 있는지 의아해질 것이다. 당연히 CocoStudio를 어떻게든 활용해보려는 발버둥을 치며 삽질을 했던 스토리를 포스팅하기 위해 쓴 글이므로 CocoStudio에 대한 이야기를 할 것이다. 앞에서 언급했던 중요한 문제는 바로 UI 배치였다. 게임을 만들면서 연출해야 할 UI는 한 두개가 아니다. 작은 게임이라 하더라도 많은 UI가 필요하며, 경험해봤으면 알겠지만 UI를 구현할 때는 정말 괴롭다. 무엇보다도 힘든 것은 코드 레벨에서 UI를 배치하는 것이다. 그나마 나는 Lua binding을 이용하기 때문에 괴로움이 덜한데, UI가 적절한 위치에 넣어졌는지 숫자를 계속 바꿔가면서 확인을 해봐야 한다면 정말 괴롭지 않겠는가? 그냥 되는 것도 아니고 컴파일까지 해야한다. 


이 때문에 UI 툴은 필수적이다. 엄청난 생산성 향상을 가져올 수 있을 뿐만 아니라, 더 좋은 품질의 게임을 개발할 수 있는 기반이 된다. 문제는 이러한 툴을 만드는 것이 쉽지 않다는 것. C#에서 Window form 툴 마냥 드래그해서 컴포넌트 배치해줄 수 있게 하는 등의 기능을 구현하는데만 긴 시간이 필요하다. 그렇기 때문에 울며 겨자먹기로 코드 레벨에서 UI를 구현하는 경우도 분명 많을 것이다. 내가 Unity를 보고 가장 부러웠던 점은 Unity가 기본적으로 실시간 게임 화면을 보여주기 때문에 이런 툴이 구지 필요 없다는 점이었다. 대신 그들도 NGUI와 같은 것을 쓰긴 하지만... 


Cocos에서는 이러한 툴로 유명한 것이 CocosBuilder였다. (지금은 SpriteBuilder라는 이름으로 새롭게 시작하는 듯 하다.) 사실 나는 CocosBuilder를 써본 적이 없어서 잘 모르겠다. 내가 이러한 문제에 관심을 가질 때 등장한 것이 바로 CocoStudio였다. Cocos2d-x 팀에서 직접 개발한 Graphical Interface Builder였고, CocoStudio에서 Export한 Scene 데이터를 읽어와 Node를 생성해줄 수 있는 기능을 Cocos2d-x에 내장하여 새로운 버전이 릴리즈 되었다. 


이 CocoStudio를 처음보고 굉장히 큰 감명을 받았었는데, 직접 써보니 정말 구렸다. 처음 쓸 때는 중국어 밖에 지원이 안됬던데다가 온갖 버그가 많았다. 지금도 부족한 부분은 여전히 많긴 하다만 많이 나아진 상태이다. 무엇보다도 공수가 많이 드는 Graphical Interface Build 부분을 공짜로 이용할 수 있다는 점에서 메리트가 있다고 생각했다. 이것을 이용해서 UI 개발을 할 수 있으면 참 좋겠다는 생각을 한 것이다. 결정적으로 결론을 내리게 된 계기는 최근에 Anchor Point 기능이 추가되면서였다. 해상도, 종횡비가 다른 디바이스가 많기 때문에 Left-top, Right-top 과 같이 앵커포인트를 이용하여 UI 배치를 할 수 있어야 하는데, 그 기능이 드디어 추가됬던 것이다. 


하지만 여전히 문제는 있었다. 가장 큰 문제는 버튼과 같은 것들의 Callback 기능을 툴 상에서 제공해주지 않는 다는 것. 그렇기 때문에 CocoStudio에서 Node를 관리할 때 Tag를 사용한다는 것을 이용하여야 한다. CocoStudio에서 Export된 json을 이용하여 SceneNode를 생성하고, SceneNode의 자식들 중 원하는 자식을 Tag로 찾아낸 다음, 직접 Callback을 등록해주어야 한다. 또한 커스텀 UI 컴포넌트를 이용하고 싶을 수 있는데, 그러한 경우에도 직접 툴 상에서 그것을 추가할 수 없다. 뭔가 GUI 관련 클래스를 굉장히 열심히 구현해놓은 것 같은데 정작 쓸모가 별로 없다. -_-;;



내가 생각한 해결 방법은 다음과 같다. 

1. Designed Resolution을 정한다.

2. UI 배치는 Graphical하게 보여지는 CocoStudio에서 한다.

3. CocoStudio에서 만든 Scene Node에서 해당 노드를 바꿔치기 or 수정한다.



그.러.나....

CocoStudio를 활용하는 것을 포기하고, SpriteBuilder(구. CocosBuilder)를 활용하는 쪽으로 방향을 바꾸었다.

CocoStudio의 가장 큰 문제점은 사용하기 어렵다는 것이다. 굉장히 많은 시간을 투자했는데도 불구하고, 도대체 어떻게 활용하는 것이 다중 해상도 지원에 좋은 것인지 모르겠다. 내부 소스 또한 깔끔하게 정리되어 있지 않아 불편했다. CocoStudio 부분을 이리저리 수정하면서 방법을 모색해봤지만.... 결국 실패다 -_- 

CocoStudio 쪽 관련해서 내가 커밋 활동을 좀 해보던가 할까 싶다.


물론 SpriteBuilder를 활용하는 것에도 문제가 있다. 바로 SpriteBuilder 측에서 Cocos2d-x를 지원해주지 않고 있다는 것. 그나마 다행인 것은 CocosBuilder 시절 소스가 남아있어서 이것을 수정하면 된다. (사실 내가 작업중이다 - https://github.com/growingdever/cocos2dx-ccbreader)

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday