이 짧은 글로 당신의 WME 게임 제작 과정 전체를 안내해주려는 것은 아닙니다. 하지만 게임 개발 중에 길을 잃어버린 것 같은 사람들에게 작은 지침을 제공하고자 합니다. 여기서 저는 제 경험을 제공하겠지만 그에 대해서 사용 허가가 필요하지는 않습니다. 이 글을 쓰게 된 동기는 IRC 채널에서 했던 개인적인 잡담들에서 비롯되었고, 그로 인해 저는 제 생각을 관심이 있는 모든 사람들에게 말로 전하게 되었습니다. 저는 이건 정말 지옥으로 가는 길이라고 경고하고 싶을 정도로 더럽고 지저분한 코드를 꽤 많이 봐왔습니다. 제가 말하는 것들이 똑똑한 척하는 것으로 들릴 수도 있습니다. 하지만 저를 믿으세요. 자기 자신에게 가혹할 수록 제작은 더욱 쉽게 진전됩니다. 또한 이 튜토리얼은 초보자들을 위한 것으로 숙련된 사람들은 뭔가 혁신적인 발견을 할 수는 없을테니 다른 곳으로 가는 게 좋습니다.
자, 그럼 시작해봅시다.
당신은 분명히 어느 날 갑자기 게임을 만들어야 겠다는 생각이 떠올랐고, 당분간 그것을 간직하다 생각을 좀 더 현실적인 것으로 바꾸어야 겠다고 결심했습니다. 당시에는 정말로 그 생각의 결과에 대해 실감할 수 없었을 겁니다. 게임을 했을 때는 아주 단순하고 다루기 쉬워 보였지만, 그걸 가지고 뭔가 시작하자 과정 그 자체에 압사당하는 자신을 발견했을지도 모릅니다.
당신을 재포장하기 위해, 몇 가지 분명한 사실들을 언급해보겠습니다. 당신의 일반적인 어드벤처 게임은 사실 멀티미디어 프로젝트이고 몇 가지 주요한 기초 요소로 이루어져 있습니다.
퍼즐은 어디 있고, 인터페이스는 어딨냐고 생각할지도 모릅니다. 제게 퍼즐과 인터페이스는 스토리의 일부입니다. 저는 스토리에 대한 타당성 없이는 절대 게임에 퍼즐을 넣지 않습니다! 시간 제한이 있는 미로 퍼즐이나 슬라이더 퍼즐 같은 것이 매우 흔하다는 것은 알고 있지만, 그것이 스토리에 딱 맞지 않는 한은 게임에 넣을 이유가 없습니다. 따라서 이것들은 스토리의 부분이고 스토리는 퍼즐의 존재를 정당화하기 위한 것이 아닙니다.
스토리. 어드벤처 게임의 핵심. 왜 너무 많은 팀들이 적절하고 견고한 스토리 없이 특수효과나 코딩부터 시작할까요? 장담하건데, 그렇게 시작한 프로젝트는 금방 깨지고 말 겁니다. 그러니까 심지어는 WME를 실행하기도 전에 퍼즐 설계가 포함되어 완성된 스토리와 인터페이스에 대한 생각, 장소의 지도, 아이템 명세서 등이 '디자인 문서'에 있어야 합니다. 이런 것들은 WME를 만지거나 특수효과 담당자를 보채서 많은 그림을 만들어내지 않아도 할 수 있는 것들입니다. 이와 함께 부족한 팀 멤버를 채울 개연성을 가지고 있어야 합니다. 요즘 인터넷에는 게임을 만든다고, 다른 게임들을 넘어설 거라고 말하는 사람들이 넘쳐납니다. 만약 그게 사실이라면, 우리는 그 엄청난 사람들이 만든 엄청난 게임들을 즐기느라 게임을 만들 이유가 없을 겁니다. 슬프게도 그런 일은 없기 때문에 우리는 우리 스스로에게 기여해야 합니다.
좋아요, 여기서 게임 디자인에 대해서는 너무 많이 파고들지 않는 게 좋겠습니다. 왜냐면 주변에 더 나은 자료들이 많이 있는데다 제가 말하고자 하는 건 WME 게임 제작에 있어서 핵심적인 측면들입니다. 어떤 것들은 정말로 구체적이어서 처음부터 올바르게 따라하면 성과를 볼 수 있을 겁니다. 이어지는 상황을 상상해보세요. 당신이 당신의 초 사기스러운 게임을 만들다가 1/3 지점에서 깨달았습니다. 당신은 수천줄의 코드를 다시 써야만 하는 디자인 플로우를 만들어 버렸노라고. 행복할까요? 혹은 뭔가 익숙한 상황인가요? 솔직히 말해 저도 저런 적이 있습니다. 자, 이제 수다는 충분하니 좀 더 구체적인 것으로 들어갑시다.
성공적인 프로젝트의 공통점은 그것을 다루기 쉬운 더 작은 덩어리들로 나누었다는 겁니다. 아니라면 당신은 커다란 덩어리 속에서 길을 잃게 될 겁니다. 주된 몇몇 덩어리들은 프로젝트를 알기 쉬운 양식으로 관리할 수 있게도 해줍니다. 우리는 이미 우리가 가지고 있는 멋진 도구에서 당신의 프로젝트를 어떻게 나누는지에 대한 아이디어를 찾을 수 있습니다. WME는 패키지 시스템이라는 훌륭한 기능을 가지고 있습니다. 어떻게 이용할까요? 프로젝트 디렉토리에 다량의 디렉토리를 만들고 나서 프로젝트 관리자에서 그것을 마우스 오른쪽 버튼으로 클릭한 뒤, Promote to Package(패키지로 만들기)를 선택합니다. 이제 이 디렉토리로부터 패키지를 만들 것입니다. 따라서 기본적인 해답을 따를 경우 프로젝트 디렉토리에 다음의 폴더들을 만들고 그들을 패키지로 만들수 있습니다.
당신은 여전히 모든 것이 하나의 큰 패키지에 들어가는 것을 선호할지도 모릅니다. 뭔가 크게 다른 거라도 있을까요? 상상해보세요. 당신의 국제 친구와 게임을 테스트하는데 단순한 코딩 실수를 범했습니다. 당신은 간단하게 1MB도 안 되는 data 패키지를 수선해 보내면 됩니다. 400MB도 될 수 있는 GFX는 함께 보낼 필요가 없죠.
제 분할은 여기서 끝나지 않습니다. WME는 패키지 제작에 있어선 정말 멋져서 각각의 게임 속 장소를 논리적으로 나누어 패키지로 분할할 수도 있습니다. 데이터나 스크립트의 끊임없는 증가를 더 분명하게 관리할 수 있을 뿐 아니라, 당신의 팀원들과 동시에 디버그하고 테스트하기도 쉽습니다. 당신의 게임을 다루기 쉬운 작은 덩어리로 쪼갠다면 좌절하는 일을 줄일 수 있을 겁니다.
디버그를 도왔던 코드들 중에 제 가장 크게 불평했던 것은 정말 끔찍하고 읽기 어려운 문자 배열을 가진 것입니다. 그런 경험을 한 것은 저 혼자만이 아닐 것으로, 불쌍한 Mnemonic은 더 엄청난 것들을 봐왔을 겁니다. 코딩을 할 때는 좋은 규칙을 몇 개 가지고 그것을 따르는 것이 좋습니다. 제가 모든 블록들을 정렬하는 것처럼요. 여기 그 예가 있습니다.
method HelloWorld() { var greeting; switch (language) { case "german": greeting = "Hallo"; break; case "english": greeting = "Hello"; break; case "swahili": greeting = "Jambo"; break; } }
이 형식은 코드를 즉시 읽기 쉽게 만들어줍니다. 뭔가 이성적인 서식으로 고치는 데 10시간을 소비할 필요도 없구요. 다음으로 중요한 건 주석입니다. 주석은 비겁하다는 철학으로 사는지는 모르겠지만, 그 무엇도 진실에서 멀어질 수는 없습니다. 주석은 미래에 필요할지도 모릅니다. 게임은 10분 안에 입력할 수 있는 13줄짜리 코드가 아니니까요. 게임 개발은 최소한 몇 개월은 걸리는 일이고 디버깅을 기다리는 멋진 버그들을 엄청나게 만들어낼 겁니다. 물론 예전에 못 쓰게 된 코드에 대해 잊어버릴 수도 있고, 무엇이 이 배열에 뒤죽박죽이 된 글자를 집어넣는 이상한 루프를 불러오는지 밝혀내느라 애를 먹을 겁니다. 주석이 없으면 길을 잃습니다. 그리고 제발 "주석은 나중에 달 거야"라는 식으로 생각하지 마세요. 진실은, 당신이 십중팔구 주석을 달지 않게 된다는 겁니다. 그러니까 미리 주석을 쓰고, 나중에 고통스럽게 기억해내지 않는 게 낫습니다. 그러면 제 다른 원칙을 살펴봅시다.
절대 주 프로젝트에서 실험하지 마세요. 당신이 뭔가 예측할 수 없는 것을 실험하기로 했다면, 별도의 WME 프로젝트를 만들어서 그 생각을 시험하는 것은 정말 쉬운 일입니다. 종종 그걸 잊어버리곤 합니다. 당신의 주 프로젝트가 파괴된 채로 발견되는 것, 최소한 더러워지는 것을 원하진 않을 겁니다. 주 프로젝트를 깨끗한 코드만 남겨두는 곳으로 생각하세요. 누구도 당신이 시험용 폴더를 만들어 지저분한 방법을 사용하는 것을 막지 않습니다. 하지만 진짜에 그것을 포함시키로 했다면, 깨끗하게 만드세요(비누도 써서)!
자, 다음으로 큰 문제, 변수와 오브젝트를 살펴봅시다. 저는 이미 이들에 관해 튜토리얼을 쓴 적이 있고 여기서 볼 수 있습니다. 하지만 지금 당장 저는 의미론에 대해 말할 겁니다. 정말 명백한 실수인데, 당신의 코드를 a, a1, a2, a3 같은 이름의 변수로 채우는 겁니다. 만약 당신이 SuperVariable15나 MyLittleBlueDaisy라는 이름의 변수를 만드는 게 멋지다고 생각한다면 문제는 더 심각해집니다. 그런 이름은 코드 자체에 비해 전혀 타당성이 없습니다. 지금이야 그게 좋은 생각이라고 할지 몰라도, 이후에 6개월 전 만든 버그를 찾아보려 애쓰며 당신을 자책하게 될 겁니다. 제 충고는 정말 엄격해야 한다는 겁니다. 변수의 이름을 그것이 하는 일에 따라 지으세요. 그러니까 루프를 위한 변수라면, 그와 관련된 이름을 짓지 않을 이유가 있나요?
더 나쁜 상황은 전역 변수에서 나옵니다. 만약 아직도 당신의 a, a1 을 믿고 있다면, 지역 변수와 전역 변수에 똑같은 변수를 사용하는 일이 생길 수 있습니다! 이것은 당신의 스크립트를 예측할 수 없게 만들고 당신을 알코올 중독자나 더 심하면 르네상스 음악을 듣는 사람으로 만듭니다. 반면, 전역 변수를 위한 접두사를 만드는 등 어떤 체계를 만들어 사용한다면 그럴 일이 없을 겁니다. 만약 아직도 어떻게 해야 할지 모르겠다면, 여기 작은 예시가 있습니다.
global gDoorEntity; var DoorEntity; ... ... DoorEntity = "open"; gDoorEntity = "closed";
살펴보면 어떤 변수들이 첨부되었는지만이 아니라 어떤 것이 전역 변수고 어떤 것이 지역 변수인지도 알 수 있습니다. 전혀 헷갈릴 일이 없죠.
이제 변수에 대한 생각이 분명해졌다면 오브젝트에 대해 생각해봅시다. 이것 역시 앞서 말한 튜토리얼에서 다루었지만, 다시 한 번 다루어 봅시다. 잘 기술된 아래의 예제보다 별도의 변수 세 개를 쓰고 돌봐야 하는 것이 더 쉽다고 확신할 수 있나요?
var DoorEntity; DoorEntity.State = "open"; DoorEntity.X = 120; DoorEntity.Y = 70;
switch를 다음 문제로 삼아봅시다. 기억하세요. if는 악이다 너무 많은 if는 코끼리를 죽이고 그린피스에 소송당할 수도 있습니다. 또한 if의 과한 사용은 지옥으로 끝날 수도 있습니다. 이제 진지하게, 어떻게 case를 사용하는지 배우고 그것을 사랑해봅시다. 다시 작은 예제를 듭니다.
switch (DoorEntity) { case "open": actor.GoTo(100,20); break; case "destroyed": actor.GoTo(100,20); actor.Talk("We shouldn't hand those zero gravity guns away so easily."); break; case "closed": actor.Talk("I can't walk through closed door. Wait for Hopkirk."); break; }
더 많은 선언문들이 포함될 수 있는데, case가 정말 멋지고 분명하지 않나요?
자, 당신을 지루하게 만들어 죽이기 전에 마지막 기술적인 문제를 말하겠습니다. 들으세요. WME는 훌륭한 문서를 가지고 있다. 그걸 어떻게 읽는지 배워봅시다. 진지하게 말하는 겁니다. 발생하는 문제의 97%는 거기 숨어있습니다! 가끔 chm 파일을 살펴보는 것보다는 포럼에 질문을 올리는 것이 더 낫다고 느껴질 때고 있습니다. 부끄러워요. 우리는 문서에 이미 써진 것이 아닌 다른 것을 토론하며 생산적으로 시간을 사용할 수 있습니다. 물론 저를 포함한 모두가 뭔가 분명한 것들을 물어보는 시기를 거쳤습니다. 하지만 제발 문서부터 봐주세요. 가끔 문서에 나온 사실을 언급하고선 "그건 아직 보지 않았는데요"라고 말하는 걸 보면 웃기기도 합니다. 만약 찾는 게 없다면 자유롭게 물어보세요. 하지만 먼저 할 것이 있죠. 문서를 보세요.
이것들이 제가 당신에게 전해줄 수 있는 팁들입니다. 다른 생각이 나면 더 추가될지도 모르겠지만, 지금 당장은 다 썼습니다. 조금이라도 유용한 것을 찾았길 바라고, 흥미로운 새 어드벤처 게임도 볼 수 있길 바랍니다.