로그인

회원가입 | ID/PW 찾기

연재

게임 개발에 사용되는 도구들 ②

게임 프로그래머 문기영의 ‘게임 프로그래머 이야기’ 12화

ProgC 2015-03-16 12:36:53

이번에도 역시 게임 개발 도구에 대해 알아볼 것이다. 이번에는 레벨 에디터, 소스 비교/병합, 소스 관리에 대해 알아 보도록 하자.

 

 

레벨 에디터


게임 개발에서 반드시 있어야 하는 도구 중에 하나는 바로 레벨 에디터 혹은 맵툴이라고 하는 도구다. 게임의 장르에 따라 레벨 에디터의 모양은 다르겠지만, 게임 플레이의 바탕이 되는 부분이 레벨이기 때문에 레벨 에디터가 거의 필수적으로 사용된다.

 

공개용 맵 툴 Mappy

 

레벨 에디터를 갖추고 있으면 게임 개발을 진행할 때 변경에 있어 매우 자유롭다. 예를 들어 맵의 구조를 변경한다 거나 새로운 게임 플레이 기능을 추가할 때 레벨 에디터가 있으면 더 적극적으로 변경을 시도할 수 있다.

 

※ 노트: 더 적극적으로 변경할 수 있다는 것은 보통 좋은 신호다. 게임 개발에 있어 기술적인 제한 때문에 문제가 있음에도 수정을 하지 못하는 것은 재밌는 게임을 만드는데 걸림돌이 되곤 하기 때문이다.

 

예를 들어 4 x 4짜리 맵을 단순히 프로그래밍 언어의 배열로 표현하면

 

 

int map[] = { 1,1,1,1,

1,0,0,1,

1,0,0,1,

1,1,1,1}; 

 


이때 1은 벽을 뜻하고 0은 빈 공간을 뜻한다. 현재는 맵에 적의 위치, 플레이어의 위치, 아이템 위치 같은 것들이 없다. 단순히 벽과 걸어 다닐 수 있는 빈 공간만 표현한 것이다. 만일 다른 형태의 맵을 만들거나 테스트할 때 레벨 에디터가 없다면 프로그래머가 손수 데이터를 수정해주어야 하는데, 이것은 명백한 시간 낭비다. 이러한 작업은 레벨 디자이너라는 전문가가 따로 있으며, 이 시간에 프로그래머가 다른 게임 개발 도구를 작성할 수 있도록 스케줄을 편성하는 것이 더 현명한 선택이 될 것이다.

 

레벨 디자이너가 Mappy와 같은 도구를 이용해 맵을 만들고 나면 프로그래머가 이 맵 데이터를 사용하게 된다. 물론 이러한 데이터는 컴퓨터가 이해할 수 있는 데이터로 바뀌어야 하는데, 레벨 에디터가 있으면 이러한 변환 과정도 모두 알아서 처리해 준다.

 

 

const short TEST21111_map0[50][50] = {

{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0 },

{ 0, 0, 0, 0, 0, 141, 141, 141, 141, 141, 141, 141, 141, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0 },

{ 0, 0, 0, 0, 0, 141, 159, 163, 1, 1, 164, 160, 141, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0 },

{ 0, 0, 0, 0, 0, 141, 161, 151, 158, 157, 150, 162, 141, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0 },

{ 18, 137, 0, 0, 0, 159, 163, 156, 141, 141, 155, 164, 160, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0 },

{ 36, 137, 1, 1, 1, 1, 1, 162, 148, 141, 161, 1, 1, 1, 1, 1, 

1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 1, 1, 1, 1, 143, 

117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 

0, 0 },

{ 37, 137, 1, 1, 1, 1, 1, 164, 160, 159, 163, 1, 1, 1, 19, 1, 

1, 1, 23, 1, 1, 1, 1, 1, 1, 1, 1, 19, 1, 1, 1, 1, 

135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 1, 1, 1, 

135, 0 },

{ 38, 137, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 

1, 1, 1, 1, 1, 1, 1, 19, 1, 1, 1, 1, 1, 1, 1, 1, 

143, 117, 0, 0, 0, 0, 136, 36, 37, 137, 0, 116, 142, 58, 59, 60, 

143, 117 },

{ 37, 137, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 

1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 

1, 135, 0, 0, 0, 134, 136, 18, 36, 137, 3, 1, 23, 78, 79, 80, 

1, 1 },

{ 36, 137, 1, 1, 1, 1, 1, 1, 1, 23, 1, 1, 1, 1, 1, 20, 

1, 1, 1, 19, 1, 1, 1, 1, 1, 19, 1, 1, 1, 1, 1, 1, 

1, 143, 117, 0, 116, 142, 136, 37, 18, 137, 2, 1, 1, 96, 97, 98, 

1, 1 },

 

… 생략

 

};

 

const unsigned short TEST21111_cmap[256] = {

0x0000, 0x000B, 0x4D6A, 0x04A0, 0x0697, 0x258C, 0x04E1, 0x035F,

0x1909, 0x14C6, 0x59AA, 0x362D, 0x0438, 0x29CF, 0x6739, 0x2C00,

 

… 생략

 

0x0426, 0x0C48, 0x18C6, 0x5633, 0x42B6, 0x2DD0, 0x51D0, 0x39D4,

0x0C68, 0x097F, 0x2C63, 0x2110, 0x084A, 0x4E11, 0x42B5, 0x148C,

0x2DF0, 0x5212, 0x1CD6, 0x258D, 0x3191, 0x1D4A, 0x1CEC, 0x0000

}; 

 

맵 데이터의 내부

 

이러한 데이터를 손으로 만들어야 한다고 상상해보자. 게임 개발이 결코 즐겁지 않을 것이다.

 

 

레벨 에디터의 기능들


보통 개발하고자 하는 게임에 따라 레벨 에디터의 모습이 다르지만 공통적으로 사용되는 기능들이 존재한다. 가장 기본적으로 오브젝트를 배치하는 것이다. 위치를 표현하기 위해 좌표값이 필요한데 2D게임이라면 X, Y 2개의 좌표가 필요하고 3D게임이라면 X, Y, Z값이 필요할 것이다.

 

이러한 좌표값을 프로그래머 혹은 레벨 디자이너가 손으로 작업하게 되면 그만큼 불행한 일도 없을 것이다. 그래서 보통은 도구가 존재하고 레벨 디자이너가 배치하고 싶은 오브젝트를 선택하고 이것을 배치하게 끔 해주는 기능들이 존재한다.

 

3D World Studio

 

※ 노트: 3D World Studio는 다음 사이트에서 다운로드 받을 수 있다. //www.thegamecreators.com/?m=view_product&id=2100&page=Downloads


드럼통 하나를 움직이려면 마우스 클릭으로 손쉽게 선택 가능하다.

 

드럼통을 선택한 모습.

 

화면의 오른쪽 부분을 보면 탑 뷰에서 레벨을 볼 수 있는데 현재 선택된 드럼통을 볼 수 있다. 이제 이것을 그림과 같이 오른쪽으로 움직여 보자.

 

선택된 드럼통을 오른쪽으로 움직여 보았다.

 

이제 3D공간에서 드럼통의 위치가 변한 것을 확인할 수 있다.

 

왼쪽에 있던 드럼통을 오른쪽으로 움직였다.

 

레벨 디자이너는 이러한 도구들을 이용해 게임 레벨을 만들어 낸다. 지금 예를 보인 것은 단순히 물건을 배치하는 수준이지만, 필요에 따라 오브젝트는 회전을 하기도 하며 크기가 바뀌기도 한다. 이쯤에서 우리가 즐겨했던 게임들의 게임 레벨이 어떻게 구성되었는지 생각해 보자. 예를 들어, GTA같은 게임들의 전체 레벨을 구성하려면 얼만 큼의 노력이 필요할까?

 

※노트: GTA5를 만드는데 얼마나 많은 사람들의 노력이 필요했는지 궁금하다면 다음 사이트를 확인 해보자. //en.wikigta.org/en-wiki/wiki/Credits_(GTA_V)​

 

 

이벤트 처리


레벨 디자이너가 배치하는 오브젝트들은 대부분 움직이지 않는 것들이다. 하지만 어떠한 조건에 따라 배경의 한 오브젝트가 움직이거나 몬스터를 만들어 내려면 어떻게 해야 할까? 블리자드는 예전부터 자신들이 만든 게임의 맵 에디터를 공유해왔는데, 이것을 살펴 보면 배울 것이 매우 많다.

 

스타크래프트2의 맵 에디터의 모습.

 

예를 들어 어떠한 유닛이 죽을 때, 이 유닛이 주인공이라면 “게임 오버”라는 메세지를 화면에 띄우고 싶다고 하자. 보통 이러한 내용은 프로그래머가 코드를 작성해 주어야 한다. 예를 들어

 

 

void UnitDied(Unit unit)

{

if ( unit->mTypeName == "Jim Raynor" )

{

System.Exec(GameOver);

}

}

 


위의 코드는 가상의 코드이며 유닛이 죽을 때 UnitDied라는 함수가 호출되고 내부적으로 이 유닛의 타입을 검사해 Jim Raynor라면 시스템에 게임이 끝났다고 알리는 것이다. 스타크래프트2의 겔럭시 에디터의 경우 이러한 작업을 코드 없이 구현했는데 그림과 같이 노드로 표현했다.

 

이벤트 트리거를 코드 작업 없이 구현하고 있다.

 

그림을 살펴 보면 Events는 어떠한 유닛이라도 죽으면 호출이 되고 로컬 변수는 없으며, 조건이 있는데 만약 유닛이 Jim Raynor라면 Actions으로 대화 상자를 띄운다는 것이다. 재밌는 사실은 앞서 살펴본 코드와 매우 유사하다는 점이다. 이처럼 최근의 게임 개발 추세는 코드 작업을 없애고 레벨 디자이너에게 이러한 것들을 맡겨서 게임이 더 재밌게 만들어 질 수 있도록 환경을 제공하는 것이다.

 

※ 노트: 겔럭시 에디터의 경우 이벤트를 만들고 나면 내부적으로 루아(Lua) 스크립트 코드로 변환한다. 루아라는 것에 대한 자세한 내용은 //www.lua.org/ 을 참고 하도록 하자.

 

 

소스 비교

 

프로그래머는 하나의 게임이 완성되기까지 매우 많은 코드를 작성하게 되는데, 경험이 쌓이면 쌓일 수록 이러한 코드를 잘 관리하는 것이 매우 중요하다. 프로그래머가 작성하는 코드를 소스(Source) 코드라고 하는데 이러한 소스들은 사람이 읽을 수 있는 텍스트로 구성되어 있다.

 

두 개의 파일을 비교한 모습.

 

오른쪽에 있는 것이 현재 수정하고 있는 버전의 소스이고 왼쪽이 변경하기 이전의 파일 내용이다. 더 확대한 다음 그림을 살펴 보자.

 

더 확대한 모습.

 

왼쪽에 float mY = 0.5f;라는 소스 코드는 오른쪽에서 왼쪽에 public이 붙은 것을 확인할 수 있다 그리고 NavMeshAgent mAgent;가 새로 추가된 것도 확인할 수 있다. 마지막으로 public이 PlayerState에 추가되었다.

 

이처럼 원본을 가지고 있을 경우에 해당 소스에서 어떠한 수정 작업을 하면 그 수정된 내용과 범위를 모두 알 수 있다. 이것이 소스 비교 도구다. 이러한 도구 중에 필자가 주로 사용하는 것은 BeyondCompare라는 도구인데 사용법은 매우 쉽다.

 

우선 왼쪽에 놓을 파일에서 마우스 오른족 버튼을 눌러

 

해당 파일에서 마우스 오른쪽 버튼을 누르면 컨텍스트 메뉴가 나타난다.

 

Select Left File for Compare를 선택한다. 그리고 비교할 다른 대상의 파일에서 마우스 오른쪽 버튼을 누르면 다음과 같은 컨텍스트 메뉴가 나타난다.

 

비교할 파일을 선택한다.

 

Compare to “Player.cs”를 선택하면 비교 화면이 나타난다.

 

왼쪽, 오른쪽 파일을 비교 한다.

 

원본을 가지고 있는 경우에 수정본에서 어떠한 것들을 수정했는지 알 때 이 소스 비교 도구가 매우 큰 도움이 된다. 그렇지 않으면 일일이 코드를 읽어가며 수정된 부분을 찾아내야 한다.

 

※노트: 소스를 비교할 때 도구를 최대한 사용하자. 소스를 혼자서 관리하는 경우라도 소스 비교 도구는 꼭 사용하는 것이 좋다. 왜냐면 사람은 실수 하기 마련이고 이런 실수는 보통 찾기가 매우 어렵기 때문이다.

 

 

소스 병합


이제 소스 병합 도구에 대해 알아보자. 앞서 소스 비교툴을 이용해 두 개의 파일을 비교하는 내용을 알아보았다.

 

프로그래머 혼자서 작업하는 경우는 병합 문제가 큰 이슈가 되지 않지만 여러 명이 하나의 프로젝트에 동시에 업무를 진행할 때 소스 병합 이슈가 자주 일어난다.

 

여러 사람이 하나의 파일로 작업할 때 생겨나는 문제점.

 

그림을 예를 들어 설명해 보도록 하겠다. 프로그래머 2명이 있는데 사람1, 사람2라고 하자. 두 프로그래머가 수정할 파일은 0일 째 아무런 내용이 없다. 

 

1일. 사람1이 파일을 수정하기 시작했다. 파일의 내용에 “테스트 메세지”라고 입력.

2일. 사람2가 파일을 수정하기 시작했는데 이때 파일의 원본은 비어있다. 왜냐하면 1일 째 사람1이 파일을 수정하긴 했지만 저장하지는 않았기 때문.

3일. 사람1이 수정한 파일을 저장했다. 이때는 아무런 문제가 없다.

4일. 사람2가 파일을 저장하려고 하면 파일의 내용은 무엇이 되겠는가?

 

만일 4일 째 사람2가 저장한 파일로 파일이 저장되면 “테스트 메세지”라는 사람1이 작성한 내용은 사라지게 된다. 그렇다고 사람2가 입력한 “나도 수정 중”이라는 메세지를 저장하지 않고 사람1이 작성한 내용만 저장하게 되면 사람2가 입력한 내용은 모두 사라지게 된다. 이러한 문제를 해결하기 위해 탄생한 것이 소스 병합이다.

 

만일 사람1이 저장한 파일을 test.txt라고 하고 사람2가 저장한 파일을 test2.txt라고 하자. 그리고 이 두 파일을 비교한다.

 

두 파일을 비교.

 

사람1은 이미 저장할 때 아무런 변동 사항이 없는 상태에서 소스를 저장했기 때문에 병합을 할 필요가 없지만 사람2가 저장할 때는 파일에 변동 사항이 생겼기 때문에 이러한 소스 충돌 문제를 소스 비교 도구를 이용해서 해결해야 한다. 

 

물론 이때 “테스트 메세지”와 “나도 수정 중”이라는 메세지를 어떤 순서로 설정해야 하는지는 사람1과 사람2의 의견 일치를 보아야 한다. 만일 사람2가 “나도 수정 중”이라는 내용을 소스의 두 번째 줄(사람1이 작성한 라인과 다른 라인)에서 수정했다면 소스는 간단히 

 

 

테스트메세지

나도 수정 중 

 


으로 수정될 것이다.

 

 

소스 관리 툴


앞서 소스 비교 도구를 설명할 때 “원본을 가지고 있는 경우”라는 말을 여러 번 했다. 프로그램 소스 코드는 컴퓨터 소프트웨어를 제작할 때 가장 중요한 자산인데 그 이유는 소스가 있어야 소프트웨어를 다시 만들 수 있기 때문이다. 

 

생각하기도 싫지만 소스 코드가 사라진다면? 회사가 망하거나 해당 프로젝트를 드랍 하거나 다시 제작 해야 한다. 이러한 중요한 자산을 지키기 위해 존재하는 도구가 바로 소스 관리 툴이다. 

 

소스 관리 도구는 Microsoft Sourcesafe, SVN, Perforce,Git이 있다. 이외에 다른 소스 관리 도구들도 존재하지만 필자가 사용해본 것만 적어 보았다. 북미의 경우 거의 대부분의 게임 회사가 Perforce라는 도구를 사용하고 오픈 소스 진영에서는 Git을 사용한다. 

 

소스를 어떻게 관리하는지에 대한 주요한 차이점이 있지만, 돈이 없는 프로그래머에게 그것보다 더 중요한 것은 관리 도구가 공짜이냐 아니냐 이다! Perforce의 경우 비싼 편에 속하며 Git은 공짜다! 그래서 인디 개발자들은 SVN혹은 Git을 주로 사용한다.

 

소스 관리 도구를 사용하는 여러 이유 중에 가장 중요한 것을 나열해보면 다음과 같다.

 

소스 백업

한 명 이상의 개발자 간에 협업

분기

과거로 복귀

 

소스 백업은 정말 중요하다! 소스를 잊어버리면 프로젝트는 끝이다. 물론 본인이 작업하고 있던 프로젝트의 폴더를 압축해서 “프로젝트명_1.zip”, “프로젝트명_2.zp”와 같이 압축을 해놓고 “나는 프로젝트를 잘 백업해 오고 있어~ 헤헤”라고 생각한다면 정말 말리고 싶다. 정말 그 방법을 고집하고 싶다면 해당 파일을 최소한 다른 컴퓨터 혹은 서버에 주기적으로 백업하는 것을 스스로 하거나 자동화 시켜야 한다.

 

소스 관리 도구의 꽃은 바로 개발자 간의 협업에 있다. 앞서 소스 비교/병합 도구를 살펴 보았는데 이러한 도구들이 연계해서 사용되는 곳이 바로 소스 관리 도구다. Perforce의 경우 서버에 최신 버전의 소스 코드가 존재하는데, 이럴 경우 어느 누군가 의 컴퓨터가 데이터를 모두 날려 먹어도 다시 복구 시키는데 오랜 시간이 걸리지 않는다.

 

물론 서버에 변경된 소스를 업데이트하지 않고 오랫동안 작업했을 경우 작업 기간 동안 작업했던 결과물들을 모두 잃어 버리지만 전체를 잃어버리진 않는다. 그래서 보통 소스 관리 도구를 사용하는 경우 프로젝트에 일하는 모든 팀원이 주기적으로 소스를 서버로 업로드해서 최신 상태를 유지한다.

 

마지막으로 분기가 사용되는데 이것은 예를 들어 보도록 하겠다.

 

프로젝트를 개발하다 보면 특정 기능을 실험해보거나 특별한(?) 사람들을 위해 데모를 작성 해야 하는 경우가 있다. 만약 어떤 기능이 게임에 들어갈지 아닐지 결정하지 않은 상황에서 많은 코드를 작성해 놓은 경우 최종적으로 해당 기능을 사용하지 않는다고 결정되면 해당 코드를 프로젝트에서 없애기 위해 많은 시간이 걸리기 마련이다. 이럴 때 소스 관리 도구의 분기라는 기능을 이용하면 언제든지 기능을 넣거나 뺄 수 있다.

 

마지막으로 과거로 복귀하는 기능이다. 예를 들어 게임이 개발되고 있는 경우 어떤 QA가 버그를 발견했다고 치자. 그런데 해당 버그를 게임에서 재현 해보려고 해도 도무지 재현이 안되는 경우가 있다. 이럴 때 

 

“신이시여! 감사합니다. 버그가 사라졌어요~ 헤헤”

 

이렇게 생각하고 프로젝트를 진행하는 프로그래머는 없다고 생각한다.

 

※ 노트: 그런 프로그래머가 있다면 프로젝트가 망할 확률이 매우 높다. 완성이 되어도 결국 버그 때문에 프로젝트를 중단하게 될 것이기 때문이다.

보통은 이런 상황이 생기면 프로그래머들은 매우 스트레스를 받는다. 왜냐면 버그가 명백하게 있었는데 지금 사라졌기 때문이다. 이럴 때 과거로 복귀 기능은 매우 유용하게 사용될 수 있다. 

 

※ 노트: 심지어는 코드를 작성했는데 아무런 버그가 없어도 스트레스를 받는다. “버그가 없을 리가 없는데…” 하면서 말이다​.

소스 관리 도구는 프로젝트가 진행되면서 변경된 코드를 모두 저장하고 있는데, 그것이 몇 년이 지난 것이라고 하더라도 의도적으로 지우지 않은 이상 모두 저장하고 있다. QA가 발견한 버그를 실행했던 게임 실행 파일의 버전을 확인해보고 해당 버전이 사용한 코드의 마지막 버전으로 모든 코드가 복귀 가능하다. 

 

이렇게 과거로 돌아가 게임을 실행해 QA가 발견한 버그를 테스트 해보고 왜 그 버그가 발생했는지 알아낼 수 있다. 그제서야 프로그래머들은 마음을 놓고 “아~ 해당 코드가 사라져서 최신 버전에서는 버그가 발생 없어진 거였군~”하며 안심하게 된다. 

 

물론 “어라~ 이 코드가 사라지고 최신 버전에서는 yy부분으로 옮겨갔는데 그럼… yy부분에서 이러한 버그가 똑같이 발생하겠는 걸?”하면서 최신 버전에서 해당 버그를 고치게 될 것이다.

 

이렇게 소스 관리 도구를 사용하면 작업의 편의성도 올라가고 프로젝트의 안전성(?)도 올라간다. 결론적으로는 제품(우리가 만드는 게임)의 퀄리티가 올라가게 된다.

 

※ 노트: 본인이 1인 개발자라고 하더라도 소스 관리 도구는 반드시, 무조건 사용해야 한다고 생각한다. 프로젝트가 성공적이기 위해서​.

다음 화에서 빌드 툴, 피직스 디버거 툴에 대한 이야기를 해보도록 하겠다.

최신목록 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10