▲ 넥스트플로어 지하연구소 김영수 디렉터

[인벤게임컨퍼런스(IGC) 발표자 소개] 김영수 디렉터는 과거 넥슨에서 마비노기2: 아레나, 메이플스토리 빌리지, 메이플스토리 어드벤처 개발에 프로그래머로 참여했다. 이후 넥스트플로어에서 시프트업과 공동 개발한 데스티니 차일드에 프로그래머로 개발 과정에 참여했으며. 프로그래머이자 디렉터로서 Protocol:hyperspace Diver 개발을 주도했다. 현재 넥스트플로어 지하연구소의 미공개 신작의 디렉터를 맡고 있다.

지난 19일 넥스트플로어 지하연구소에서는 모바일 리듬게임 'Protocol:hyperspace Diver(이하 P:h Diver)'를 출시했다. 출시 전부터 'P:h Diver'는 1인 개발이라고는 믿기지 않는 퀄리티를 보여줘 많은 사람들의 관심을 받곤 했다. 하지만 1인 개발인 것보다 더 놀라운 것은, 'P:h Diver'가 김영수 개발자가 자체 개발한 엔진으로 만들어졌다는 사실이었다.

게임 개발 과정에 있어 자체 개발 엔진은 하나의 로망이다. 분명 자신들이 기획한 게임에 맞춰서 게임을 제작하는 도구이자 재료인 게임 엔진을 처음부터 구축하는 것이 좀 더 의도한 바를 명확히 드러내 줄 수 있기 때문이다. 그렇지만 게임을 개발하기에 앞서 엔진을 개발하는 과정에서 소모되는 비용이나 시간 등은 선뜻 자체 엔진 개발에 손을 내밀지 못하게 한다. 더욱이 최근에는 게임을 구동하는 플랫폼까지 다양해지면서, 플랫폼간 호환성을 확보하는 문제 등도 고민거리가 되고는 한다.

과연 자체 엔진을 개발하면서 자신이 원하는 게임을 비용과 시간을 과다 투자하지 않고, 플랫폼간 호환성 문제 등 다양한 문제를 해결해서 내놓을 수 있을까? 김영수 디렉터는 자신의 개발 경험을 통해 청중들이 자체 개발 엔진에 대해서 다른 각도에서 생각할 수 있는 계기를 마련했다.



■ 자체 엔진으로 개발한 'P:h Diver': 왜 자체 엔진으로 개발해야 했는가?


▲ 넥스트플로어에서 출시한 모바일 리듬 게임 'P:h Diver'

김영수 디렉터는 강연에 앞서 'P:h Diver'에 대해서 간략하게 소개했다. 'P:h Diver'는 지난 4월 19일 넥스트플로어에서 iOS와 안드로이드에 동시에 출시한 모바일 리듬게임이다, 그는 먼저 양 플랫폼에서 모두 지원이 되어야 했기 때문에 자연히 iOS와 안드로이드에서 동시에 지원되는 프로그램 언어인 C++기반으로 코드를 구성했다고 밝혔다. 그리고 C++기반의 로우 레벨 라이브러리에 OpenGL ES 2.0과 OpenAL을 활용해 그래픽과 오디오를 구현하는 방식으로 자체 개발 엔진을 만들고, 이를 활용해 'P:h Diver'를 제작했다고 요약했다.

뒤이어 그는 이번 강연에서 주로 다룰 부분에 대해 언급했다. 우선 'P:h Diver'와 이에 쓰인 엔진을 개발하는 과정을 기술적인 부분 위주로 되짚어가는 포스트모템의 과정을 통해 저수준의 모바일 게임 개발의 노하우를 강연에 참석한 사람들과 공유하고자 한다고 밝혔다. 아울러 엔진 개발 여부를 결정할 때 참고가 될 수 있도록 게임 엔진 개발에 드는 시간 및 비용, 자신이 개인적으로 경험한 어려운 점이나 고려해야 했던 점 등을 같이 공유하는 것도 이번 강연의 목표라고 언급했다.

▲ 강연에서 다룰 두 가지 큰 목표를 먼저 제시하고 설명을 이어갔다

이러한 일련의 과정을 위해서 그는 'P:h Diver'에 대해서 조금 더 심도 있게 조명했다. 그는 'P:h Diver' 기획에서 핵심은 '3차원 공간 상에 선과 노트가 존재하고, 음악에 따라 공간이 바뀌며, 이를 2차원인 스크린을 터치함으로써 노트를 처리하는 것'이라고 말했다. 이를 다르게 말하면 게임 내에서 3D 그래픽 출력/연출이 가능해야 하고, 사운드 출력이 가능해야 하며, 터치 입력이 처리가 가능해야 한다는 것이다.

보기에 단순한 구성이지만, 그는 좀 더 높은 수준의 리듬게임을 위해서 생각할 부분이 많았다고 밝혔다. 개발자이기 이전에 유저의 입장에서 고찰했을 때, 게임 경험에서 프레임 드랍이나 사운드 레이턴시(음향이 지연되어서 출력되는 현상)가 발생하지 않아야 했다. 그가 플레이했던 유니티 기반의 리듬 게임에서 종종 발생했던 프레임 드랍이나, 터치음의 사운드 레이턴시를 겪었을 때, 그는 이러한 요소들이 유저에게 생각보다 큰 문제가 될 수 있음을 깨달았다. 그에 따라 최소한 큐잉된 입력 처리가 될 수 있도록 하는 방법에 대해 많은 생각을 해보게 되었다고 밝혔다.

한 편으로 디렉터로서 유저에게 좀 더 편하고 좋은 UI와 UX를 제공하고 싶다는 생각도 있었다고 언급했다. 단순히 터치하는 것뿐만 아니라 스크롤 등 멀티 터치 환경에서 적절히 반응하고, UI에서 보다 '쫀득한' 조작감을 느낄 수 있도록 커스터마이징하고 싶었다는 것이다.

그도 처음부터 자신의 수요에 맞는 엔진을 개발하고자 하지는 않았다. 우선 기존에 존재하는 모바일 게임 엔진을 통해 이를 구현할 수 있는지 점검하는 과정을 거쳤다. 그가 고려한 엔진은 유니티, 모데라토, 코코스 2D이었으며, 개발에 앞서 엔진들의 특성에 대해서 검토해보았다.

우선 유니티의 경우, 개발에 앞서서 나온 '아이돌 마스터 신데렐라 걸즈(이하 데레스테)'를 통해 어느 정도 성능을 예측할 수 있었는데, 무겁고 느려서 일부 프레임 드랍이나 레이턴시가 발생하는 경우를 종종 보였다. 또한 유니티의 UI 도구들도 개인적으로 선호하지 않고, 그에게는 비교적 덜 익숙한 엔진이었기 때문에 유니티는 후보에서 제외됐다.

▲ 유니티는 좋은 엔진이지만, 그의 의도에는 맞지 않았다

그 다음에 검토한 엔진은 넥스트플로어에서 자체 개발한 모데라토였다. 드래곤 플라이트, 데스티니 차일드 등 넥스트플로어에서 개발한 게임들이 사용한 엔진으로, 검증은 어느 정도 된 상태였다. 네이티브 C++기반이라 속도도 빠른 편이고, 또한 사내에 전문가가 많아 문제가 생길 때 빠른 피드백을 받을 수 있었고, 약간의 애니메이션과 상호작용 지원이 있는 UI시스템은 그가 의도하는 UI를 구현하기에 나쁘지 않아 보였다. 그렇지만 구문법의 C++를 사용하고, 싱글스레드 기반이라는 점이 문제였다. OpenGL ES 1.1을 사용하기 때문에 쉐이더를 이용하기 어렵다는 단점도 존재했다.

▲ 전문인력에게 지원받기는 용이했지만, 엔진 자체에서 원하는 것을 지원하지는 않았다

마지막으로 검토한 엔진은 코코스2D였다. 코코스2D는 검토하던 당시(2015년) 한창 발전하고 있던 엔진으로, 네이티브 C++기반이라 속도도 보장되었고, 엔진 구조도 단순한 데다가 오픈소스여서 문제가 생기면 자체 해결이 가능하다는 장점도 있었다. 뿐만 아니라 C++11과 3D 지원도 당시에는 꽤 빠른 속도로 구현되고 있었다.

다만 김영수 디렉터 개인적으로 3.0 알파 버전부터 사용해오면서 자잘한 문제를 느꼈고, 당시 코코스2D 엔진에서 3D 지원이 막 시작하던 단계였기 때문에 엔진에 대한 신뢰도가 낮았다. 또한 괜찮은 UI/UX 프레임워크가 없다는 점과 사운드 라이브러리가 예상보다 강력하지 않다는 점 때문에 리듬 게임에 사용하기엔 적합하지 않다고 판단했다.

▲ 발전성이 있었지만, 당시에 그의 니즈를 충족시켜주지는 못했다

기존 엔진에 대한 검토를 마친 후, 김영수 디렉터는 비용 및 개발 시간에 대해서 추산했다. 여기에 추가로 그는 그 자신의 특수한 상황을 고려했다. 자체 엔진을 처음부터 만들지는 않았지만 자체 엔진 개발에 참여한 경험이 있으며, 모바일 프로젝트 경험이 있기 때문에 모바일에 최적화된 엔진 구성 및 기술적 노하우가 있었다. 더구나 'P:h Diver'의 프로그래머 및 기술 인력은 그 혼자였기 때문에 별도의 커뮤니케이션 비용이 들지 않았다.

▲ 혼자 개발한 만큼 커뮤니케이션 비용이나 부담이 적어서 시도할 수 있었다고......

상용 엔진을 쓸 경우 우선 엔진에 대해 배워야 하고, 최적화에 드는 비용도 발생했다. 한편, 자체 엔진을 개발할 경우 게임의 근간부터 개발하기에 최적화에 쉬우며 원하는 기능도 그때그때 만들어 쓸 수 있다는 장점이 있었다. 이러한 점을 추산했을 때 개발 비용이나 효용 측면도 코코스2D를 사용했을 때와 비슷할 것으로 전망했으며, 그는 좀 더 자신이 원하는 방향으로 커스터마이징하기 위해서 자체 엔진을 개발하는 방향으로 잡았다고 밝혔다.

▲ 기획 의도를 얼마나 구현할 수 있는가의 문제와 교육 비용 등도 추산했다

▲ 결론을 도출한 이상, 남은 건 실행 뿐이었다



■ 엔진 구조 및 특징 소개: 자체 엔진을 만들 때 고려해야 할 것

자체 엔진을 개발하기로 결정했을 때 그가 처음으로 고려한 것은 플랫폼 중립성이었다. 'P:h Diver'는 스마트폰, 태블릿은 물론 아이폰, 안드로이드 등 수많은 제품에서 범용적으로 즐길 수 있어야 했다. 단순하게 본다면 모든 기기에 맞춰 한 땀 한 땀 포팅하는 방법도 있었지만, 그 방법은 시간도 많이 들고 100개의 기기에 맞춰 포팅을 하는데 인력도 많이 들었다.

▲ 화면에 보이는 것만 세어봐도 플랫폼 수가 상당하다

이 문제를 해결하기 위해서 그는 추상화를 채택했다. 이 방법은 플랫폼별 구동 로직을 밑에 깔고, 그 위에 플랫폼 중립적인 게임을 만드는 방식으로, 컴퓨터 공학에서 많이 쓰이는 방식이었다. 다음으로는 어떤 언어를 쓸 지에 대해서 생각해보았다. 우선 각 플랫폼에 사용하는 언어를 분석했을 때 아이폰은 스위프트와 오브젝티브 C++을 주로 쓰고, 안드로이드는 자바나 C++ via NDK(Native Development Kit)를 쓰는데 C++는 양 플랫폼에서 모두 네이티브로 지원했다. 그래서 프로그래밍 언어로 C++를 선택했다.

또한 엔진이 표준 C++를 이용하면서 기존에 C++을 활용하는 OS, 라이브러리들과 호환이 가능했으며, 플랫폼을 제공하는 POSIX 라이브러리도 사용이 가능했다. 또한 표준 라이브러리와 표준 템플릿 라이브러리(STL: Standard Template Library)도 다양한 곳에서 사용 가능해진다는 장점이 있었다. 이런 점을 통해서 호환성 문제의 상당 부분을 해결할 수 있다는 장점도 있었다. 아울러 iOS와 안드로이드 모두 C++ 기반의 IDE 갖췄기 때문에 런타임 디버깅이 가능한 환경을 구축하기 용이했다.

플랫폼 그래픽 라이브러리와 사운드 라이브러리를 정할 때에도 호환성 측면과 기능을 고려를 해야 했다. iOS와 안드로이드 둘 다 OpenGL ES 2.0을 지원했으며, 쉐이더를 지원하는 장점도 있었다. 사운드 라이브러리의 경우 OpenAL을 사용했는데, iOS에서는 바로 지원이 되었고 안드로이드에서는 포팅을 통해서 사용이 가능해서 호환성에서 큰 문제가 없었다.

아키텍처에서는 iOS와 안드로이드에서 차별화를 두었다. 기본적으로 iOS와 안드로이드가 C++ 코드를 런(Run)할 때 구조상에 차이가 있기 때문이다. 안드로이드의 기본 플랫폼 코드는 자바 코드이며, JNI(Java Native Interface)를 통해서 C++ 코드와 통신하는 방식이다. 따라서 프래그먼트 액티비티와 렌더러는 자바로 하고 라이브러리는 C++로 구성했다. 반면 iOS는 C 언어에서 파생된 오브젝티브 C++를 이용하기 때문에 GLKView를 이용해서 비교적 단순하게 구성할 수 있었다.


▲ 설계할 때 각 플랫폼마다 다른 점을 염두에 두어야 한다

이와 같은 틀을 짤 때 윈도우와 맥에도 대응하는 것도 고려했다고 밝혔다. 특히나 윈도우의 경우, 개발 중 가장 빠른 이터레이션이 가능한 플랫폼이면서 디버깅도 용이했다. OpenGL ES를 이용했을 때 ESL을 통해서 호환이 가능했다는 점도 있었다. PC에서 OpenGL을 사용해서 개발했을 경우, 모바일에서는 호환이 되지 않는 경우가 발생한다. 그가 개발하고자 한 엔진과 게임은 모바일이 퍼스트 클래스였기 때문에, 최대한 모바일 환경과 동일하게 갖춰진 상태에서 개발을 해야 한다는 점에서 OpenGL ES 이용 가능 여부도 중요했다.

▲ '디버깅', 자체 엔진 개발 과정에서 자주 언급된 내용이다. 그만큼 자주 하게 되고, 중요한 과정이다

틀을 잡고 난 뒤에 김영수 디렉터는 바로 구현하기보다는 호환성부터 확보했다. 우선 플랫폼을 추상화시켜 공용 플랫폼을 구성하고, 공용 플랫폼의 로직 위에 기능별 인터페이스를 구현하는 방식으로 호환성을 확보하는 과정을 거쳤다. 그리고 엔진의 각 부분 기능은 모듈로 격리해서 정리하고, 모듈별로 게임 코드 레이어에 게임 객체의 생성을 위임함으로써 원하는 순서대로 게임을 구동할 수 있도록 했다. 엔진에는 생성 함수의 인터페이스만 존재하도록 구성해 게임에서 이용할 기능에 맞춰 게임 엔진을 구성했다.

▲ 종합했을 때 이와 같은 구조를 갖게 되었다



■ 저수준 개발 경험 공유: 개발 과정에서 겪을 수 있는 문제와 해결 과정

'헬로 월드', 저수준 개발에서 가장 먼저 접하는 구동의 방식이다. 이렇듯 구동이 되게 하는 과정은 크게 어렵지 않다. 그렇지만 그 위에 텍스처 등을 덧씌우고, 구현하는 것부터 점차 어려워진다. 그림 파일을 읽고, 이를 디코딩하고, OpenGL 텍스처에 올리는 과정 등 복잡한 절차를 거쳐야 하기 때문이다. 김영수 디렉터 또한 이 과정에서 어려움을 겪었다고 밝히면서, 저수준 개발에서 문제를 해결한 과정에 대해 차근차근히 짚어갔다.

먼저 텍스처 관리에서, 그래픽스에 필요한 기능은 상당히 많았다. 저수준에서 개발할 때 특히 막막한 부분은 OpenGL 텍스처 부분인데, 이 과정에서 그는 PNG파일을 적극 활용했다. PNG 파일은 투명도, 비트 색상 등 필요한 기능을 거의 갖췄기 때문이다. 텍스처 생성 과정은 추상화를 해둔 뒤, 디코더를 붙이는 방식을 취했다. 이렇게 하면 디코더를 붙여서 텍스처를 언제든 로드할 수 있었기 때문이다.

텍스처를 로드하는 방법은 libpng로 디코드해서 빌드하는 과정을 우선 거쳤다. 그리고 비트맵으로 메모리에 뽑은 다음, OpenGL ES 텍스처에 업로드했다. 이러한 방식으로 앱을 만들어가다가 텍스처가 일부 날아가는 경우도 발생할 수 있다. 앱이 백그라운드로 넘어가거나 하는 경우도 발생하는데, 안드로이드의 경우는 setPreserveEGLContextOnPause를 설정해서 막을 수 있다.

이미 발생한 경우에는 체크하고 복구를 해야 하는데, 앱이 백그라운드에서 돌아올 때 기존 텍스처를 체크하고 텍스처가 날아갔는지 여부를 gllsTexture 함수를 통해 검사해야 한다. 그렇지만 발생했을 때 복구하기 위해서는, 설계할 때부터 복구를 위한 메커니즘을 구성해야 한다. 'P:h Diver'에서는 관리되는 텍스처가 생성될 때 복구 함수를 함께 전달하는 방식으로 텍스처가 날아갔을 때에도 복구가 가능하도록 메커니즘을 구성했다.

▲ 종종 글쓰다가 갑자기 종료됐을 때, 복구 기능이 얼마나 중요한지 알게 되는 것과 같다

멀티스레딩과 텍스처, 섀어드 컨텍스트를 이용해서 컨텍스트간 데이터를 공유하면 멀티스레딩과 데이터를 공유할 수 있고, 비동기 텍스처 로딩이 가능하다. 이를 통해 사용자에게 60프레임 화면을 계속 유지하게 하면서, 처리하는데 소요되는 시간도 줄어든다. 다만 이와 같은 경우에는 동기화에 유의해야 한다. 동기화되지 않은 텍스처를 사용할 경우 충돌이 발생할 수 있기 때문이다. 또한 비표준적인 동작에도 주의할 필요가 있다고 덧붙였다.

▲ 동기화할 때 표준에서 벗어난 것들은 충돌이 일어날 수 있으니 유의

저수준에서 보다 저장 공간을 효율적으로 사용하고 성능을 향상시키기 위해서는 여러 스프라이트를 하나의 이미지에 모은 '텍스처 아틀라스'가 중요했다. OpenGL에서 드로우 콜(Draw Call)을 줄이면서 텍스처를 사용할 수 있기 떄문이다. 정적 텍스처 아틀라스는 아티스트와의 협업 과정에서 많이 사용되는데, 툴의 출력을 읽어 사용할 수 있게 구현해야 좀 더 효율적으로 협업이 가능해진다. 런타임에도 glTexSubImage2D 등 함수를 이용해 텍스처 부분 업로드가 가능한데, 이 과정에서 부분 텍스처를 받을 때 복구 함수를 함께 받아 저장한다거나 하는 등 복구 메커니즘에 유의할 필요가 있다. 텍스처는 언제나 날아갈 수 있기 때문이다. 2차원 냅색 문제의 경우는 박사 학위 논문이 있을 정도로 심도 깊은 문제지만, 바이너트리 등 적당한 알고리즘을 통해 어느 정도 해결은 가능하다고 언급했다.

▲ 그림을 한 곳에 모아둠으로서 각 요소를 개별적으로 콜하는 수고를 덜었다

▲ 데이터는 언제나 날아갈 수 있으니 항상 준비해야 한다

▲ 굉장히 복잡한 문제지만, 적당히 풀 수 있는 방법이 있으니 찾아보길 권했다

추가로 렌더 타겟 텍스처와 프레임 버퍼 등을 구현하면 용이하게 활용할 수 있다. 렌더 타겟 텍스처는 GL이 렌더링하는 타겟(프레임버퍼)을 텍스처로 설정하는 것으로, 프레임 버퍼의 내용을 텍스처로 카피가 가능해지면서 스크린 효과 등 여러 가지 렌더링 효과를 넣을 때 유용하게 쓸 수 있다.

이미지가 아닌 텍스트의 경우, 흔히 하는 '헬로 월드'는 프로그래밍에서 '콘솔'을 통해서 텍스트를 출력해낸 것이다. 그러나 모바일의 경우는 OpenGL 화면에 텍스트를 그린다, 라고 하는 표현이 더 정확하다. 텍스트를 텍스처로 만든 뒤, 텍스처를 그리는 방식이기 때문이다. 즉 문자열에 대해 글자 한 자씩 텍스처를 얻어내 그려가는 방식이다. 이와 같은 방식에서 폰트는 각 문자를 어떻게 '그릴지'에 대한 정보를 담고 있는 것이 된다. 폰트 렌더링 라이브러리를 통해 글자의 폰트 하나하나가 결정되는 것이다.

▲ 컴퓨터에서 출력되는 텍스트와 달리, 모바일의 텍스트는 텍스처로 표현된 정보다

폰트의 경우는 종류에 따라 서로 다른 글자의 모양을 가지고 있으며, 라이선스나 용량 등의 문제가 있기 때문에 이를 잘 고려하는 것이 중요하다. 또한 다른 언어에서 글리프가 의도치 않게 변하는 경우도 있기 때문에 이를 유념할 필요가 있다. 구글이나 어도비의 Noto 계열 폰트는 여러 언어에서 무난한 수준의 글리프가 제공되고, 대부분의 문자가 커버되기 때문에 고려할 만했다.

그 외에도 문자 간 간격을 조정하는 '커닝'과 여러 줄 텍스트를 정렬하고 모양새를 잡아주는 텍스트 블록 구성 역시 신경을 써야 한다. 이를 신경 쓰지 않으면 텍스트가 예쁘게 정렬되지 않기 때문이다. 개행 관련 처리도 엔진을 통해서 처리하며, 알파벳은 하이픈을 삽입하고 한글이나 일본의 가나 등은 단어 단위로 개행 힌트를 고려해야 한다. 그러나 'P:h Diver'에서는 다수의 텍스트가 삽입되지 않았기 때문에 구현하지는 않았다고 밝혔다.


▲ 위와 같은 과정을 거쳐서 좀 더 깔끔하게 텍스트 열을 다듬을 수 있다

▲ 이와 같은 부분은 텍스트 비중이 높은 게임을 개발할 때 고려해야 할 점이지만, 참고할 필요가 있다

텍스트를 예쁘게 정렬할 때 또 하나 중요한 점은, 다국어 텍스트 조판 시에 문자 종류별로 베이스라인과 크기 세팅을 해야 한다는 점이다. 이를 적용하지 않으면 언어가 바뀔 시에 글자 크기나 스타일이 각기 달라져서 지저분하게 보이기 때문이다.

UI는 공통적인 동작과 상호작용 로직을 가지는 부분이 많기 때문에 시스템화해서 사용하는 것이 좋다. 기존의 쓸만한 라이브러리가 있다면 사용하는 것도 좋지만, 'P:h Diver' 개발 당시에 OpenGL 게임과 연동해 쓸만한 추상적인 UI 라이브러리는 없었다. 그래픽 시스템, 입력 시스템에 대한 구상은 이미 갖춰졌지만 거기에 맞춘 추상적 UI 라이브러리가 없다는 것이 정확할 것이다.

▲ 자체 게임 엔진을 개발하기로 결정한 이유 중 하나

UI의 가장 중요한 역할 중 하나는 입력에 반응하는 것이다. 즉 유저가 터치하고 스크롤하는 것에 따라서 그에 맞는 반응을 보여야 한다는 것이다. 'P:h Diver'에서는 스크롤과 터치 둘 다 반응하되, 종류에 따라서 다른 반응을 보여야 했기 때문에 기존에 있던 WPF 방식 등을 참고하면서 터치 이벤트 처리 방식을 별도로 구현했다.

레이아웃도 UI에서 고려해야 할 요소 중 하나다. 다양한 종류와 해상도의 스크린에 대응할 때, 어떤 상황에서든 일정한 레이아웃을 보일 수 있어야 하기 때문이다. 초창기 스마트폰 게임 중 일부에서는 이를 고려하지 않아서 기종에 따라 버튼이 다른 곳에 있거나 화면 밖으로 나가는 경우가 종종 있었다. 이를 잡기 위한 방법 중에 자동 레이아웃이 있지만, 자동 레이아웃 외에도 절대값으로 나타나는 오프셋과 부모-자식의 상대 위치 관계로 구성하는 레퍼런스 포인트와 앵커포인트를 이용해 해상도가 변해도 스크린 상에서 틀이 유지되는 레이아웃시스템을 구현할 수 있다.

▲ 레이아웃 시스템을 구축하지 않으면 스크린 해상도가 바뀔 때마다 UI가 중구난방이 된다

UI 시스템을 구축할 때 중요한 것은, 게임에 이용되는 UI 정의를 데이터화해야 한다는 점이다. UI의 경우 아티스트들이 수정하기도 하고, 자잘한 부분을 계속 개선해나가는 경우가 많다. 이럴 때 데이터화는 빠른 이터레이션을 가능하게 하고, 자잘한 것을 옮길 때 컴파일을 다시 하는 수고를 하지 않게 해준다.

▲ 데이터화는 가구 하나 옮기는데 집을 다시 들었다놨다하는 격이 되지 않도록 해준다

또한 UI는 영역 내 계층 구조로 이루어지기 때문에, 이를 담을 수 있는 마크 업 언어 정도는 만들어서 사용하는 것이 좋다. 'P:h Diver'의 경우 XML 기반으로 디스크립션(Description)이라는 마크업 언어를 만들어서 사용했다. XML은 이미지, 텍스처 등을 다 담을 수 있는데, 이를 정리해서 오브젝트화하고 프리펩으로 만든 뒤, 임포트해서 사용할 수 있게 구현한 것이다.

▲ 마크업 언어를 만들고 계층 구조를 담아두면 변수, 프리펩을 활용하기 용이해진다

사소한 부분일지 모르지만, 처음부터 다국어 대응을 고려해두는 것이 편하다. 나중에 고치려고 하면 기본부터 고쳐야 할 수 있기 때문이다. UTF-8의 경우 상호운용성이 뛰어나고, 플랫폼 간 상호 변환도 간편한 편인데다가 성능도 나쁘지 않아 사용할 만하다.

모바일의 경우는 각 OS별 파일 시스템에 대해서도 알아둘 필요가 있다. 윈도우는 개발용으로 따로 존재하기 때문에 그냥 사용하면 되지만, iOS의 번들은 파일이며, 안드로이드의 번들은 압축된 어떤 데이터 형태이기 때문에 구현하기 위해서는 std, stream 등 추상화시키는 로직을 통해 구현하는 게 편하다. 그리고 파일이 저장되는 저장소 클래스의 구분도 필요하다. 내부 저장소나 외부 저장소, 에스디 카드 등 저장소의 종류마다 독립적인 추상화를 통해서 로직을 짜지 않으면 대응을 못할 수도 있기 때문이다.

사소한 팁으로, 엔진 개발을 할 때 공용 로그 함수부터 만드는 것이 좋다. 로그는 디버깅의 기본이기 때문이다. 하나의 함수로 NSLog, 안드로이드 Log 등으로 다 출력될 수 있도록 하는 게 좋다. 윈도우에서는 OutputDebugString 함수의 이용을 고려하는 게 편하다.

▲ 디버깅은 항상 유념해둬야 한다

유틸리티 라이브러리를 활용하는 것도 큰 도움이 된다. C/C++ 기반이기 때문에 다양한 라이브러리와 호환성을 가지고 있기 때문에 미리 연동해두면 여러 모로 쓸 데가 있고 편리해진다.



■ 사용 자원 추산 및 고찰: 과연 개발한 의미가 있었을까?

자체 엔진 개발할 때 가장 우려스러운 부분이 이 부분이다. 과연 어느 정도 자원이 들었고, 효과가 얼마나 있을 것인가? 개발기간은 얼마나 걸릴까? 두려움이 앞서는 부분이다.

'P:h Diver'의 경우, 기본적인 큐브를 구현해내는데 1달 반이 소요됐다. 단순히 큐브를 구현하는 것이 아니라, 공용 로직 코드를 통해서 기본적인 모양을 구현하고, 쉐이더와 그래픽 기능 구현 등 기반을 구성하는데 그만큼의 시간이 소요된 것이다.

▲ 이것만 구현한 것이 아니라, 이것을 구현하기까지의 과정을 설계하는데 소요된 시간이다

그 뒤로 한 달 뒤, 개시일로부터는 2달 반 지났을 때 1차 프로토타입까지 완성되었다. 그래픽 리소스까지 올리는 데는 1달이 더 소요됐으며, 정식으로 비주얼을 갖췄을 때는 개시일로부터 5달이 지나있었다. 그리고 게임 플레이까지 가능하게끔 틀이 완성되기까지는 2달이 더 소요됐다. 즉 7개월 동안 개발해서 엔진을 만들고, 그 엔진으로 게임의 틀을 만들어낸 것이다.

▲ 지금과 어느 정도 유사한 형태를 갖추는데 총 7달 반이 소요되었다

'P:h Diver'의 규모는 록 메트릭스를 통해서 측정했을 때 엔진의 기능에 해당하는 코드는 약 8만 개였다. 전체 코드는 총합 17만 개 가량이었다. 맨먼스 추산은 혼자 개발했으며, 자체 엔진에 대한 경력이 어느 정도 잡혀있다고 봤기 때문에 14 맨먼스 정도로 추정되었다. 실질적으로 게임 개발에서 프로그래머 한 명 당 추산은 10맨먼스 정도로 잡았다.

▲ 사용된 코드 추산은 이와 같다

그렇게 개발해낸 'P:h Diver'의 목표는, 안정적으로 출시하고 이상 없이 구동하는 것이었다. 서비스 초기에 일부 문제가 있었지만, 패치를 통해서 해결한 이후 추가로 크래시가 보고되는 경우가 없다는 점에서 목표를 달성했다고 볼 수 있다.

▲ 어쨌든 썩세스, 그리고 지금도 큰 이슈 없이 구동 중이다

일부는 엔진부터 개발하면 어떤 것이 좋은지 물어볼 것이다. 김영수 디렉터는 이에 가장 좋은 점은 기술적인 요구사항을 충족할 수 있다는 점을 들었다. 스마트폰 기종이 바뀌고 새로운 기능이 생기거나 펌웨어 업그레이드 등이 이루어졌을 때, 이에 대처하기가 상용엔진을 사용했을 때보다 훨씬 쉽기 때문이다. 또한 엔진을 팀이나 프로젝트에 맞춰서 개량하기도 용이하며, 생각보다 구현비용이 크지 않기 때문에 나름 도전할 만한 부분이 있다고 보았다.

▲ 김영수 디렉터가 말하는 자체 엔진 개발의 장점

다만 파편화된 기기에 맞춰 최적화하기가 어렵고, 출시 전까지 어떤 애로사항이 발생할지 모른다는 단점도 존재했다. 또한 엔진이 나오기 전까지는 게임이 못 나오기 때문에 개발 병목 현상이 발생할 수도 있었다. 게임에 필요한 기능이 늦게 구현되면 그만큼 개발이 늦어지게 되고, 또한 인력이 중간에 교체되었을 때 기존 인력과 신규 인력의 간극을 메우는데 비용과 시간이 좀 더 투자된다는 점도 분명 단점이다. 그리고 팀 환경과 툴, 개발환경에 따라서 나오는 엔진이 천차만별일 수 있고, 그 때문에 자신들이 만들어낸 결과가 아쉬울 수도 있다.

▲ 장점이 있으면 단점도 존재하기 마련이다.

결론적으로 'P:h Diver'는 하나의 사례일 뿐이다. 각자가 처한 개발 환경이나 여건, 개성 등이 다 다르기 때문에 이에 맞춰 일률적으로 언급할 수 없다. 그저 이를 기술적인 관점에서 리뷰하면서, 자체 엔진을 개발하려는 뜻이 있는 사람들에게 어떤 참고 사례가 되었으면 하는 것이 김영수 디렉터의 바람이자, 강연의 핵심이었다.