실행아이템의 실패 동작
인벤토리는 주로 아이템을 기록하는 용도로 사용하지만 프로젝트에 따라 그렇지 않을 때도 있습니다. 그런데 이런 시도는 종종 아주 어려운 동작을 정의해야만 하는 상황을 만듭니다.

우리가 게임 상에서 발생한 가치를 미리 정의된 표준에 따른 모양으로 만들어 게임 상에서 다루기로 결정하는 순간부터 게임 상에는 아이템 개념과 아이템을 다루기 위한 온갖 규칙이 필요해집니다. 아이템은 주로 게임 상에서 획득한 재화를 보관하고 표시하는 방법으로 고안되었습니다. 오크를 사냥해 획득한 오크가 걸치고 있던 별 가치 없는 천 조각은 일단 아이템 모양으로 플레이어의 인벤토리에 보관됩니다. 초창기 온라인 게임은 이 천 조각을 곧이곧대로 인벤토리에 그 스케일에 따라 표시하기도 했습니다. 이는 실제 세계의 규칙을 따른 단순한 방법이기는 합니다만 게임 상에서 사용하기에는 그리 편리하지 않았습니다. 실제 세계와 달리 게임 상에서는 온갖 종류의 물건을 아이템 모양으로 획득했고 이들을 고작 마우스 포인터만 사용해서 정리하고 또 원하는 물건을 찾기에는 실제 세계의 경험에 비해 훨씬 제한적인 방법일 수밖에 없었습니다. 같은 규칙은 실제 세계에서 커다란 자루에 든 여러 가지 물건을 주변에 풀어 놓고 원하는 물건을 시각과 촉각, 청각 등을 활용해 찾을 수 있었지만 게임 상에서는 그럴 수 없었습니다. 이론 상 바닥에 물건을 내려 놓고 원하는 물건을 찾거나 물건을 정리하는 행동은 불가능하지 않았지만 모든 사람들이 지나다닐 수 있고 바닥에 놓인 물건을 집을 수 있는 세계에서 이는 사실상 불가능한 방법이었습니다. 사람들은 게임 제작사가 금지하는 인벤토리를 읽어 정리된 별도 인터페이스에 표시해 주는 애드온 프로그램을 거의 필수로 사용했습니다. 시간이 조금 지나고 나타나는 다른 비슷한 장르 게임들은 이 한계를 인정하고 실제 세계의 규칙과는 다르지만 인벤토리에 들어온 모든 물건을 단위 크기에 따라 커지는 모양으로 표시해 이전과 같은 탐색과 정리에 대한 부담을 크게 줄이면서도 실제 세계의 규칙과 너무 멀리 떨어지지 않는 적당한 상태를 유지했습니다.
한 번 실제 세계의 규칙으로부터 멀어지기 시작한 아이템과 인벤토리는 곧 아이템 크기에 따라 단위 크기의 배수로 인벤토리 공간을 차지하는 형태로부터 벗어났습니다. 이 역시 한동안은 가장 작은 아이템은 정사각형 모양의 인벤토리 한 칸을 차지하지만 이보다 크기가 큰 장비류는 더 많은 칸을 차지하고 금속 갑옷처럼 아주 큰 물건은 가로 두 칸, 세로 세 칸을 차지하는 것이 이상하지 않다고 생각했습니다. 새로운 아이템을 획득하면 부피가 큰 아이템 사이사이로 부피가 작은 아이템을 끼워 넣어 인벤토리를 정리하곤 했는데 이 역시 실제 세계의 규칙과 비슷할 수 있었습니다. 물론 실제 세계에서 커다란 금속 갑옷을 얻었다면 그 안에 아주 많은 작은 물건을 넣을 수 있어 무게가 무거워질 수는 있었겠지만 모든 물건의 크기는 커다란 금속 갑옷보다는 작았겠지만요. 이는 어쩌면 모든 물건이 인벤토리 안에서 가장 작은 단위 크기의 배수의 크기를 가지며 서로 줄을 맞춰 정렬되는 실제 세계의 규칙을 깨는 더 단순한 규칙을 사용하며 발생한 결과입니다. 하지만 길을 가다가 짊어지고 있는 가방 속 물건을 정리하는 행동은 실제 모험 중 일어날 법한 일인 것은 사실이었습니다. 하지만 이 역시 현대에 가까워질수록 점점 더 단순화 됩니다. 어떤 게임은 어느 순간 아예 모든 아이템은 인벤토리 안에서 같은 최소 단위 크기를 차지하도록 규칙을 바꿉니다. 이 결정은 개발하는 입장에서 여러 가지 이점이 있습니다. 일단 인벤토리 안에서 서로 다른 단위 크기의 아이템이 존재할 때 이들을 옮기고 정렬하고 검색할 때 훨씬 단순한 로직만 만들면 됩니다. T자 모양의 낫이 가로 3칸, 세로 3칸의 그리드 중 1번부터 시작해 1, 2, 3, 5, 8번 칸만 차지한다면 이를 처리하기는 어렵지는 않지만 꽤 귀찮습니다. 하지만 모든 아이템이 인벤토리에서 단 한 칸만 차지한다면 아이템이 여러 칸을 차지하는 시나리오 자체를 아예 고려하지 않아도 되니 인벤토리에 대한 여러 처리가 훨씬 단순해집니다.
또 아이템 에셋을 만드는 단계가 훨씬 단순해집니다. 만약 아이템이 인벤토리의 여러 단위 칸을 차지한다면 아이콘 에셋을 이에 따라 맞춰 그려야 합니다. 물약은 인벤토리의 가장 작은 한 칸을 차지하는데 여기에 맞춰 물약 아이콘을 그리면 됩니다. 그런데 앞서 소개한 T자 모양의 낫은 총 다섯 칸에 걸친 아이콘을 그려야 합니다. 그림을 그리는 것 자체는 다른 아이콘을 제작하는 것과 별로 다르지 않을 수 있습니다만, 이 그림이 인벤토리 상의 다섯 칸에 걸쳐 잘 나타나도록 에셋을 규칙에 맞게 제작하는 것은 또 다른 이야기입니다. 여전히 현대에 가까운 시점에 출시된 몇몇 게임들은 이 규칙을 여전히 단순화된 모양으로 유지하기도 합니다. 가령 디아블로 4에는 무기, 방어구 아이템은 여전히 인벤토리 상에서 두 칸을 차지합니다. 단 이들은 항상 두 칸을 차지하며 더 큰 아이템이나 더 작은 아이템에 관계 없이 항상 두 칸 만을 차지합니다. 그리고 나머지 아이템은 여전히 가장 작은 한 칸을 차지합니다. 이 경우는 과거의 흔적이 지금까지도 남아 있는 소수의 사례이고 이제 우리 주변에서 아이템과 인벤토리 개념이 있는 게임 거의 대부분은 모든 아이템이 한 단위 칸 만을 차지합니다. 다만 실제 세계와 연관이 조금씩 줄어들며 현대에 이르는 과정에서 그 모든 규칙을 버리지는 않았는데 지금까지도 남아 있는 실제 세계의 규칙과 연결된 아주 느슨한 특징은 과거에 여러 칸을 차지했던 아이템들은 인벤토리 안에서 아이템 한 개가 한 번만 쌓일 수 있는 반면 보석, 물약 같은 과거에도 인벤토리 한 칸을 차지하던 아이템들은 여러 번 쌓을 수 있다는 점입니다. 금속 갑옷은 과거에는 인벤토리의 여섯 칸을 차지했지만 이제 한 칸 만을 차지합니다. 하지만 두 번째 금속 갑옷을 획득하면 이전 아이템 옆의 새 칸에 추가됩니다. 반면 물약은 종류가 동일하다면 기존 물약과 같은 자리를 차지하며 인벤토리 구석에 숫자가 1에서 2로 변할 뿐입니다. 이는 이제 현대적인 게임의 인벤토리에 거의 남지 않은 실제 세계로부터 기인한 규칙의 거의 마지막 남은 흔적이라고 할 수 있습니다.
게임을 만들며 인벤토리에는 게임의 여러 기능을 인벤토리로 가져오려는 움직임과 게임의 여러 기능을 인벤토리 밖으로 옮기려는 움직임의 두 가지 큰 움직임이 있습니다. 먼저 게임 기능을 인벤토리 밖으로 옮기려는 움직임에는 재화를 인벤토리로부터 분리해 아이템 모양이 아닌 단순한 숫자로 처리하려는 것이 있습니다. 초기 게임에서 게임 상에 통용되는 재화는 아이템이었습니다. 재화라고 하니 잘 와 닿지 않을 수 있으니 여러 게임에서 통용되곤 하는 골드라고 부르겠습니다. 골드는 나머지 물건과 똑같은 아이템이었습니다. 물약 한 개를 얻거나 인벤토리 한 칸에 물약 100개를 쌓을 수 있는 규칙은 골드에도 똑같이 적용됩니다. 몬스터가 드랍한 골드는 인벤토리 한 칸에 단 한 개만 보유할 수 있지만 골드 여러 개, 또는 수 천 개나 수 만 개를 인벤토리 한 칸에 보유할 수 있었습니다. 이 시대에는 우리들이 그저 온라인 게임일 뿐인 단순한 소프트웨어를 우리들의 아주 작은 실수로 복잡계 문제로 바꿔버리는 실수를 자주 저질러 놓고 우리들이 무엇을 하고 있는지 조차 잘 모르곤 했고 이는 지난 본질 드리븐 디벨롭먼트에 소개했습니다. 이런 실수의 일환으로 이 시대에는 개인 간 거래를 허용했기 때문에 골드를 거래 상대가 원하는 금액 만큼 정확히 분리할 수 있어야 했습니다. 상대가 가진 높은 등급 방어구를 구입하기 위해 1만3천 골드가 필요하다면 인벤토리에 한 덩이로 뭉쳐져 있는 15만 골드 중 1만3천 골드를 분리해 인벤토리 상의 독립된 칸에 보유했다가 거래할 때 정확히 이 금액 만큼을 거래 창에 올려 놓고 거래를 실행해야 했습니다. 그래서 인벤토리 한 칸에 여러 개가 겹쳐져 있는 아잍템을 정확한 수 만큼 분리하는 기능이 필요했습니다. 하지만 우리들이 여러 차례의 아주 값비싼 시행착오를 겪으며 우리들이 무슨 짓을 하고 있는지 깨달은 다음부터는 더 이상 게임을 복잡계 문제로 만들지 않기 위해 노력했고 이에 따라 인벤토리 한 칸에 겹쳐진 아이템을 분리할 필요가 없어졌습니다.
왜 현대 게임에 그렇게 많은 종류의 재화를 사용하나요?와 수많은 재화를 지탱하는 보조 장치에 걸쳐 현대 게임에 다양한 재화가 필요하고 규칙을 상당히 복잡하게 만들면서도 이른 체계를 유지하는 이유를 설명했습니다. 이 역시 큰 줄기에서 이 모든 시스템이 단일 재화에 의해 통합된 모양으로 동작할 때 너무 쉽게 게임 소프트웨어가 우리들이 더이상 통제할 수 없는 복잡계 문제로 바뀔 수 있기 때문에 그럴 가능성을 최소화 하기 위함입니다. 그런데 이렇게 재화 종류가 늘어나면서 이전과 같이 인벤토리에 골드를 보관하는 방식으로 여러 가지 재화를 편리하게 관리할 방법이 필요했습니다. 이미 인벤토리에는 그저 화폐 역할을 수행하는 코퍼, 실버, 골드의 세 가지 아이템이 굴러다니고 있었고 여기에 서로 다른 컨텐츠로부터 나온 보상이 서로 게임 상에 미치는 영향을 제한하기 위한 갖가지 서로 다른 보석 모양의 재화들도 있었습니다. 이런 아이템의 종류가 늘어날수록 과거 장비 아이템이 인벤토리의 여러 칸을 차지해 이를 정리하기 곤란한 것처럼 여러 재화 아이템이 인벤토리를 차지하며 이들을 정리하고 관리하기는 점점 더 어려워집니다. 게임이 운영을 시작한 다음 시간이 흐르면 흐를수록, 상위 컨텐츠가 더 많이 나올수록 이들로부터 발생한 재화가 나머지 경제시스템에 뒤섞여 해결하기 어려운 문제를 일으키지 않도록 하기 위한 재화 종류는 계속해서 늘어납니다. 재화는 어느 덧 열 개를 넘어서고 이들을 인벤토리에 나머지 아이템과 함께 다루데 한계가 찾아옵니다. 이 문제를 해결하기 위해 주요 재화는 인벤토리로부터 분리되어 별도 인터페이스에 숫자 모양으로만 나타납니다. 여러 게임에서 더 이상 골드는 인벤토리에 아이템 모양으로 존재하지 않습니다. 골드는 인벤토리 인터페이스의 별도 자리에 숫자 모양으로만 표시되며 게임에 따라 호면 한 쪽 구석에 항상 아이콘과 숫자를 함께 표시하기도 합니다. 골드 뿐 아니라 주요 컨텐츠로부터 나온 서로 다른 재화 역시 마찬가지입니다.
반대로 이전에는 인벤토리를 경유하지 않았거나 처음부터 아이템 모양이 아니었지만 현대에 가까워지며 아이템 모양으로 만들어 인벤토리를 경유하도록 만들기도 합니다. 가령 어떤 던전에 조건을 잘 맞춰야만 들어갈 수 있는 비밀 공간이 있다고 해 봅시다. 이 비밀 공간은 던전 플레이나 클리어에 영향을 주지 않지만 맞추기 꽤 어려운 조건이 충족될 때 평소에는 절대 열리지 않던 문이 열리고 그 안쪽 공간에 들어갈 수 있고 공간 안에서는 게임 상에서 이미 죽은 NPC가 숨어 있어 NPC로부터 상황 설명을 들을 수 있습니다. 그런데 이 공간에 숨어 있는 NPC에게 먹을 것을 가져다 주기 위해 여러 차례 방문하면 ‘NPC의 친구’라는 업적을 획득할 수 있다고 해 봅시다. 이 업적을 만들기 위해서는 일단 플레이어가 이 공간에 들어왔는지 여부를 평가해 공간에 들어온 횟수를 별도로 기억하고 있어야 합니다. 이 횟수는 아마도 서버 재시작에도 불구하고 살아 남아야 할 테니 데이터베이스 어딘가에 기록해야 할 것 같습니다. 한동안 서버 프로그래머들에게 이런 요구사항을 설득하는 것은 상당히 난감한 문제였습니다. 게임 상에 이런 제각기 다른 조건에 따라 횟수를 세어 값을 저장할 일이 늘어났는데 ‘아니 그럼 이 모든 것을 데이터베이스에 저장하란 말인가요?’라는 날 선 질문을 듣기 일쑤였습니다. 지금 와서 생각해보면 당당히 ‘네'라고 대답할 만한 질문이었지만 그 시대의 저는 그러면 안 되는 줄 알고 제가 무슨 큰 실수라도 지저른 것 마냥 위축되곤 했습니다. 저는 게임 데이터베이스를 다뤄본 적은 없지만 웹 프로그램에 연동된 관계형 데이터베이스를 다뤄본 적은 있습니다. 실은 그래서 서버 프로그래머가 하는 말이 무슨 의미인지 완전히 모르지는 않습니다만, 다른 소프트웨어 개발 업계에서 프로젝트 밖에서 '클라이언트’로써 만나곤 하는 요구사항을 말하는 사람들을 프로젝트에 수직 계열화 시킨 이상 요구사항을 충족할 방법을 찾는 것이 맞습니다. 그래서 이런 횟수를 서버 재시작을 넘어 안전하게 보관하려면 데이터베이스에 이를 기록해야 하고 수 많은 플레이어들에 걸쳐 수 많은 이런 서로 다른 어떤 행동 횟수를 기록할 적절한 방법을 찾아야 하는 것도 맞습니다.
우리가 그렇게 하자고 할 때는 결국 데이터베이스 스키마를 그렇게 매번 추가할 수 없다는 판단을 받아 결국 실행할 수 없었지만 이런 다양한 행동 횟수를 그때그때 확장해 가며 데이터베이스에 저장하고 활용하는 해외 게임이 딱 하나 나타나자 그 때부터는 우리도 비슷한 요구사항을 내고 이를 실현할 수 있게 되었습니다. 가장 최근에 경험한 이런 사례에는 게임 세계 곳곳에 숨겨진 아이템이 있는데 게임디자이너는 이를 온갖 고약한 수법을 사용해 숨기고 고객들은 이를 돌파해 숨겨진 아이템 하나하나를 찾아냅니다. 각 지역에서 이 아이템을 몇 개 찾았는지, 어떤 아이템을 찾았고 어떤 아이템은 아직 찾지 않은 상태인지를 모두 별도로 기록해야 할 뿐만 아니라 업데이트에 따라 이 아이템은 계속해서 추가되었습니다. 때문에 아이템의 추가에 따라 계속해서 명시적인 저장 방법을 확장해야 했습니다. 이전 같으면 앞서 실제로 들은 말인 ‘데이터베이스 스키마를 매번 수정하기 어렵다’는 말 대신 이를 기록할 제가 생각하기에도 아주 적당한 방법을 제안 받아 계속해서 추가되는 숨겨진 아이템을 추가할 수 있었습니다. 누군가 먼저 실행한 사례를 보이기 전까지는 설득이 불가능하기는 하지만 영원히 그 상태에 머무르지는 않아 다행입니다. 또 현대에 몇몇 프론티어들은 이런 상황에 스키마 수정 부담이 없는 모양으로 확장할 수 있는 전용 데이터베이스를 사용하기도 하는 모양입니다. 게임 소프트웨어 개발 분야에는 도입이 좀 늦거나 성능이 우선시되는 상황에서 보수적인 결정을 내릴 수밖에 없기에 도입이 늦는 경향이 있어 보이지만 다른 여러 업계에서 이를 도입하고 있어 이와 비슷한 메커닉을 설계하고 제안하는 게임디자인 입장에서 부담이 좀 더 줄어들지 않을까 싶은 조금은 희망적인 생각이 듭니다.
이야기가 좀 샜는데 다시 숨겨진 공간과 거기 있는 NPC를 만난 횟수를 기록했다가 업적을 달성하게 만들려 할 때 전통적인 접근을 한다면 이 횟수를 기록할 데이터베이스 구조를 별도로 만들어야 합니다. 이를 키 밸류 스타일로 저장하지 않는다면 매번 이런 새로 기록할 숫자가 나타날 때마다 열을 추가하고 이 테이블의 행에는 모든 플레이어들이 늘어서 있는 거대한 테이블을 만들어야만 했을 겁니다. 이런 테이블을 만들고 관리해야 한다면 매번 스키마를 추가하기 어렵다는 말을 아예 이해하지 못할 것은 또 아닙니다. 하지만 해외에서 이런 기능을 사용한 게임이 나타나거나 프로그래머의 기술적 선택과 판단에 개입해 키 밸류 스토어나 스키마를 고정하지 않는 저장 방식을 사용할 것을 종용할 수는 없으면서도 여전히 NPC를 만난 횟수를 기록하고는 싶을 때 게임디자인 관점에서 저장 방식에 대한 고정관념을 조금만 바꾸면 똑같은 기능을 만들면서도 이전까지 이를 격렬하게 거절하던 프로그래머를 설득할 수도 있습니다. 바로 인벤토리를 사용하는 것입니다. 처음에는 NPC와 이야기 할 때마다 NPC로부터 다른 곳에서는 얻을 수 없는 ‘감사 편지’ 같은 아이템을 얻도록 합니다. 이 아이템은 다른 아무데도 쓸모가 없지만 인벤토리에 쌓입니다. 이 아이템 열 개를 모으면 업적에 기록하고 아이템을 제거합니다. 이제 NPC를 만난 횟수를 기록하기 위해 데이터베이스 스키마를 바꾸느니 마느니 하는 게임디자인 관점에서 쓸모도 없고 생산적이지도 않으며 기술적 배경이 부족함에 따라 압도적으로 불리한 입장에 놓일 수밖에 없는 대화를 이어 갈 필요 없이 그냥 아이템을 주고 이를 아무 코드 수정 없이 인벤토리에 보관하며 업적 시스템은 단지 미리 정해진 아이템 수량을 세도록 만들기만 하면 됩니다. 이 방법으로 여러 게임에 걸쳐 특정 행동의 횟수를 기록하면서도 서버 프로그래머의 심기를 거스르지 않을 수 있었습니다.
여기서 한 걸음 더 나아가면 이 아이템은 사실 인벤토리 상에 표시될 필요도 없습니다. 한때 게임을 처음 만들며 가장 중요한 의사결정 중 하나는 인벤토리의 최대 크기를 결정하고 최대 크기보다 더 많은 아이템을 횓득 하려고 할 때 일어날 일을 정의하는 것입니다. 하지만 이런 결정은 개발 초기에 할 수가 없습니다. 우리는 높은 분들의 말 한 마디에 따라, 새로 출시된 다른 게임에 따라 인벤토리에 아이템을 가득 채웠다가 균열 끝의 대장장이에게 부탁해 한 번에 정리해 버리는 스타일로 플레이 하는 게임일 수도 있고 인벤토리 한 칸 한 칸이 너무나 소중해 이를 철저히 관리해야 하기 때문에 인벤토리를 확장하는 유료 상품을 판매해야만 할 수도 있습니다. 초반에 이런 의사결정을 의미 있게 수행하기는 불가능합니다. 하지만 우리들은 항상 이런 의사결정을 초반헤 수행해야 하는 압력을 받곤 하는데 이제 와서 생각해보면 이 역시 한 테이블의 가로 방향으로는 인벤토리 최대 칸 수 만큼 칼럼이 늘어서 있고 세로 방향에는 모든 플레이어들의 이름이 적힌 행이 늘어선 테이블을 만들어야 했다면 인벤토리의 최대 칸 수에 그렇게까지 집착하고 이를 프로젝트 초반에 결정하게 만들려는 이유를 납득할 수 있을 것 같기도 합니다. 다행스럽게도 현대에는 인벤토리 칸 수가 이전 시대만큼 큰 의미를 가지지 않는 경우가 늘어나고 있습니다. 앞서 설명한 대로 이미 게임이 서비스를 계속함에 따라 게임 상의 여러 경제 시스템을 격리하기 위한 다양한 재화가 나타나면서 인벤토리 최대 칸 수를 강하게 제약하고 이를 고객이 관리하게 만드는 플레이를 요구하기에 게임이 그렇지 않은 모양으로 변했기 때문입니다. 그래서 인벤토리 칸 수에 사실상 제약이 없는 모양으로 만들고 또 인벤토리 최대 한도보다 더 많은 아이템을 받을 때 처리에 설명한 우편을 사용하는 방법을 고려할 수도 있습니다. 이렇게 인벤토리 최대 크기에 제약이 느슨해지거나 없어지면 그때부터는 앞서 NPC로부터 받은 아이템을 인벤토리에 표시할 필요 없이 인벤토리 데이터구조에 기록하되 이를 고객의 인벤토리 인터페이스에 보여주지 않는 방법으로 인벤토리의 역할을 기존 아이템의 보관에서 게임의 다양한 상태를 저장하는 역할을 하도록 만들 수 있습니다.
+--------------+--------------------------------------------------------------------------------------+
| | Rewards |
| +-----+--------------------+-------------------------+---------------------------+-----+
| | | Item[1] | Item[2] | Item[3] | ... |
| | +-----------+--------+----------------+--------+------------------+--------+ |
| MonstrAlias | Exp | Alias | Amount | Alias | Amount | Alias | Amount | |
+--------------+-----+-----------+--------+----------------+--------+------------------+--------+-----+
| 오크 | 200 | 회복 물약 | 1 | 찢어진 천 조각 | 2 | 오크 전사의 증표 | 1 | |
+--------------+-----+-----------+--------+----------------+--------+------------------+--------+-----+
카지노 라이크 - 1.5년 정리에 소개한 프로젝트에서 전투에 참여한 캐릭터에게 경험치를 추기 위한 방법을 고안할 때 그 전까지 사용하던 전통적인 방식의 경험치 부여 방식 대신 인벤토리를 사용한 경험치 부여 방식을 사용했습니다. 이전에는 게임 상에 골드는 아이템 모양으로 표현 및 처리되었고 경험치는 어디에도 나타나지 않는 숫자에 불과했습니다. 몬스터가 죽을 때 드랍할 보상을 입력할 때도 아이템 목록과 함께 경험치는 별도의 숫자로 표현했습니다. 이를 엑셀로 표현한다면 위 그림과 비슷한 모양이 될 겁니다. 나머지 아이템을 아이템 모양으로 표현한 것과 달리 경험치는 별도의 칼럼에 숫자로만 표시했습니다. 이런 모양은 플레이어가 한 명 뿐인 흔한 MMO 게임을 만들 때는 별로 이상하지 않았습니다. 또 골드가 인벤토리를 떠나 숫자로만 표시되기 시작한 다음에도 Exp
칼럼에 경험치를 숫자로만 표시한 것처럼 이전까지는 아이템 목록에 포함되어 있던 골드를 별도의 칼럼으로 구분해 표시하기만 하면 됐습니다. 그런데 이를 받는 캐릭터가 늘어나며 이를 표현할 적당한 방법을 찾기 어려운 상황이 만들어졌습니다. 이전과 같은 방식으로 처리한다면 경험치는 한 칼럼 상에 숫자 하나로 표현됩니다. 그렇다면 이 칼럼에 적힌 숫자를 어떤 캐릭터가 획득해야 할까요. 사실 이번 스테이지의 전투에 참여한 캐릭터에게 같은 경험치를 똑같이 지급하거나 이 경험치를 전투에 참여한 캐릭터 수로 나눠 지급하는 것으로 규칙을 정할 수 있습니다. 그런데 우리는 여기에 과거 JRPG들이 종종 채용하던 전투를 마친 다음 경험치를 획득해 어느 캐릭터에게 부여할지 고객이 결정하도록 만드는 메커닉을 사용하기로 합니다. 물론 현의를 위해 간단히 자동으로 전투에 참여한 캐릭터들에게 경험치를 분배할 수 있었지만 수동으로 원하는 캐릭터에게 경험치를 분배할 수도 있었습니다. 그런데 이렇게 만들려고 보니 경험치가 별도의 칼럼에 숫자로만 표시되어 있는 모양을 유지하기 위해서는 이 경험치를 임시로 어딘가에 가지고 있다가 고객이 경험치를 분배하는 순간까지 기다려야 했습니다.
이 상황을 처리하기 위해 앞서 설명한 경험치를 아이템 모양으로 부여하는 방식을 사용하기로 합니다. 위 테이블에서 경험치는 별도의 칼럼에 숫자로만 표시되지만 경험치를 미리 정의된 아이템과 그 수량 모양으로 부여한 다음 이를 캐릭터들에게 부여할 때 인벤토리로부터 꺼내 사용하는 겁니다. 이렇게 결정하는 순간 크게 두 가지 편리한 점이 생겼습니다. 하나는 스테이지의 시작과 끝에 보상을 표시할 때 경험치를 위한 별도의 인터페이스를 만들지 않아도 됐습니다. 경험치를 포함한 모든 보상의 형태가 아이템 모양이었기 때문에 인터페이스는 그저 아이템 여러 개가 반복해서 나열될 것을 고려하기만 하면 됩니다. 그리고 다른 한 가지 장점은 이제 경험치를 즉시 캐릭터의 현재 경험치에 더하지 않고 일단 인벤토리에 고객에게는 보이지 않는 모양으로 넣어 즉시 처리할 필요가 없어졌다는 점입니다. 고객은 자신이 필요로 할 때 경험치 부여 인터페이스에 진입해 지금까지 쌓인 경험치 총량을 확인한다음 이를 각기 다른 캐릭터에게 부여할 수 있었고 이때 인벤토리에 있던 경험치 아이템이 사용되었습니다. 한 번 이런 선택을 하자 이후 여러 가지 상황에 인벤토리를 게임 상의 여러 가지 정보를 기록하는 용도로 전용하기 시작했습니다. 인터페이스가 확장됨에 따라 여러 가지 정보를 기록하고 있어야만 했습니다. 가령 어떤 던전을 이전에 클리어 한 적이 있는지, 클리어 했다면 어떤 그레이드로 클리어 했는지, 어떤 캐릭터 조합으로 클리어 했는지, 특정 캐릭터는 특정 던전을 클리어 한 적이 있는지, 마지막으로 플레이 한 던전은 무엇인지 등 다양한 정보를 기록해야만 했는데 이는 이전에 캐릭터가 한 명일 때는 그리 복잡하지 않았지만 캐릭터가 여럿 등장하는 게임에서는 상당히 골아픈 문제였습니다. 그러니까 굳이 표현하자면 앞서 ‘데이터베이스 스키마를 그렇게 자주 바꿀 수 없다’는 피드백을 듣기 딱 좋은 그런 요구사항이었습니다. 하지만 인벤토리에 게임 상태를 기록하기로 한 이상 우리들은 프로그래머들의 의사를 묻지 않고 조용히 고객에게는 보이지 않는 던전 클리어 아이템을 던전 보상에 조용히 집어 넣고 또 특정 캐릭터의 던전 클리어 여부 역시 이를 표현하는 아이템을 조용히 만들었습니다. 매번 프로그래머와 복잡한 이야기를 할 것 없이 조용히 우리들이 생각하는 바를 구현할 수 있는 개발은 경쾌한 느낌이었습니다.
결국 프로그래머들은 우리들이 인벤토리에 표시되지 않는 아이템을 이런 식으로 광범위하게 전용하고 있다는 사실을 눈치채고 우려를 표했습니다만, 이를 수습하려면 다시 데이터베이스와 씨름하는 상황으로 돌아가야 했기에 그들은 우려 끝에 인벤토리를 처리하는 로직들을 좀 더 안전하게 손보는 쪽으로 상황을 마무리할 수밖에 없었습니다. 또한 여기서 조금 더 나아가 인벤토리를 게임 상의 여러 기능의 상태를 바꾸는 용도로 확장하기로 합니다. 가령 앞서 NPC와 여러 번 대화하면 달성할 수 있는 업적을 처리하기 위해 아이템을 사용한 이야기를 했습니다. 그런데 게임 상에는 업적과 비슷하게 딱 한 번만 열리면 그 다음부터는 그 컨텐츠에 계속해서 접근할 수 있는 요소들이 있습니다. 가령 특정 조건을 만족하면 개방되는 결투장 컨텐츠가 있다고 합시다. 그런데 결투장에 매번 접근할 때마다 그 조건을 만족한 상태인지 확인해 결투장에 진입 가능한지 여부를 판단하는 것은 안전하기는 하지만 썩 편리한 방법은 아닙니다. 조건을 만족한 고객이 게임 내 NPC에게 요청하면 결투장 입장권을 부여하도록 했습니다. 처음에는 결투장에 접근할 때 입장권을 가지고 있는지 검사하다가 나중에는 입장권을 받을 때 입장권 아이템에 데이터를 추가해 게임 상에서 결투장 컨텐츠를 개방하도록 하는 방식으로 바꿨습니다. 그러니까 결투장 입장권은 이제 인벤토리에 나타나지 않습니다. 인벤토리에 들어올 때 프로그램에 의해 결투장 컨텐츠를 개방하는 동작을 수행하도록 한 다음 수행이 끝나면 바로 사라집니다. 캐릭터 별 특수 외형 아이템은 게임 상에서 단 한 번만 획득할 수 있었는데 이 역시 보상을 받을 대 특수 외형을 개방해 주는 방식으로 동작하는 대신 특수 외형을 개방하는 아이템을 보상으로 주고 이 보상이 인벤토리에 들어올 때 아이템에 적힌 데이터를 보고 특수 외형을 개방한 다음 이 아이템은 인벤토리에서 사라지는 방식으로 만들었습니다.
+---------+---------------------------------+-----+----------------+
| | Items | | |
| +----------------+----------------+ +----------------+
| | 1 | 2 | | 100 |
| +-------+--------+-------+--------+ ... +-------+--------+
| Account | Alias | Amount | Alias | Amount | | Alias | Amount |
+---------+-------+--------+-------+--------+ +-------+--------+
| | | | | | | | |
+---------+-------+--------+-------+--------+-----+-------+--------+
하지만 여기에는 장점만 있었던 것은 아닙니다. 단점이라기 보다는 인벤토리를 이런 방식으로 활용하기 위해 지켜야 하는 단순한 규칙이 있을 뿐이긴 했습니다만, 단점으로 받아들이는 분들도 있었습니다. 만약 전통적인 게임들처럼 인벤토리 최대 칸 수에 강한 제약이 있다면 인벤토리에 함부로 정보를 기록하는 또 다른 역할을 부여할 수 없습니다. 전통적인 방식으로 만들어진 아이템 데이터베이스는 대략 위와 같은 모양일 겁니다. 이 그림을 보면 프로그래머들이 왜 프로젝트 극초반에 아이템 기능을 설계하고 개발하면서 플레이어 별 인벤토리 최대 크기에 그렇게 민감하게 반응하는지 이해할 수 있습니다. 만약 우리가 대충 200칸이라고 말하면 이 숫자는 곧이곧대로 데이터베이스 스키마넹 반영되어 나중에 이 크기를 바꾸기 위해서는 꽤 골아픈 마이그레이션 과정을 매번 거쳐야 할 수 있습니다. 이 테이블 뿐 아니라 인벤토리의 최대 크기가 200칸이라고 가정한 여러 코드가 갑자기 이상한 동작을 할 수도 있습니다. 만약 이런 방식으로 만든, 꽤 오래 된 방식으로 개발한 프로젝트라면 인벤토리의 각 칸은 굉장히 희소한 자원입니다. 고객은 이미 던전을 돌며 이 인벤토리를 이미 거의 가득 채웠거나 이미 완전히 가득 채워 아이템을 획득하지 못하고 있을 수도 있습니다. 이런 환경에서는 아쉽지만 앞서 설명한 인벤토리를 게임 상의 다양한 정보를 데이터베이스 변경 없이 기록하는 방식으로 전용할 수 없습니다. 이런 개발을 필요로 하는 기능을 아예 게임에 넣지 못하거나 이런 기능이 하나 추가될 때마다 이를 전용으로 기록하는 테이블을 수정하기 위해 지난한 설득을 거쳐야 합니다. 아이템과 인벤토리의 도메인을 확장하는 측면에서 지금까지 설명한 이런 사용은 그리 안전하지 않을 수 있습니다. 다만 직접 프로덕션 코드를 작성하지 않는 게임디자이너 입장에서 이전 같으면 달성하기 결코 쉽지 않던 요구사항을 우리들의 의지에 따라 경쾌하게 개발할 수 있었다는 점은 고무적입니다.
이미 눈치 채셨겠지만 이런 아이템을 ‘실행 아이템’이라고 불렀습니다. 실은 정확히 이 이름으로 부른 것은 아니지만 우연히 저희가 그 때 이 특수한 아이템을 부른 이름은 최근 참여하는 프로젝트에서 같은 특수 아이템을 부르는 것과 같은 이름이어서 회사에서 무서운 공문이나 전화를 받지 않기 위해 이름을 바꿨습니다. 실행 아이템은 다른 인벤토리에 표시되는 아이템과 달리 아이템에 이 아이템이 수행할 작업이 데이터 모양으로 명시되어 있고 게임 서버는 아이템이 인벤토리에 들어올 때 실행 아이템일 경우 아이템에 기입된 작업을 수행한 다음 인벤토리에서 삭제하는 방식으로 동작합니다. 실행 아이템을 도입하기 전 경험치는 다른 종류의 보상으로 표현해야 했고 여러 가지 컨텐츠 언락은 모두 각기 다른 방식의 언락 처리를 거쳐야 했습니다만, 실행 아이템은 이들 모두를 똑같이 아이템 모양으로 정규화 해 처리하게 해 주었습니다.
최근 실행 아이템을 사용하면서 이전에는 경험한 적 없는 기묘한 설계 요구사항이 있는 점을 보고 의아해 했습니다. 실행 아이템이 인벤토리에 들어올 때 인벤토리가 가득 차 있다면 어떤 동작을 해야 하는지를 정의해야 했던 것입니다. 제가 이 정의를 해야 하는 상황은 아니었지만 귀를 열어 놓고 있기에 이런 요구사항이 주변에 돌아다니는다는 사실을 모르지 않았고 의아했습니다. 근본적으로 인벤토리를 이런 방식으로 사용하겠다는 말은 인벤토리가 희소한 자원이 아니어야 한다는 전제가 필요하기 때문입니다. 인벤토리 크기에 제한이 거의 없거나 없어야만 고객의 플레이를 방해하지 않고 고객 눈에 보이지 않는 아이템을 조용히 인벤토리에 추가하거나 추가했다가 조용히 삭제할 수 있습니다. 만약 인벤토리 최대 크기가 앞서 인벤토리 최대 크기가 테이블 구조에 정의된 모양이라면 함부로 실행 아이템을 사용할 수 없습니다. 고객이 이미 플레이를 통해 인벤토리를 가득 채운 상태라면 눈에 보이는 아이템을 획득할 수 없을 뿐 아니라 실행 아이템을 획득할 수도 없기 때문에 예상하지 못한 이상한 상황이 발생할 수 있습니다. 이번 메인 퀘스트를 클리어 하면 바다를 건널 수 있는 배에 탈 수 있다고 합시다. 이 배는 컨텐츠 모양으로 정규화 되어 있고 이 컨텐츠를 언락하는 방법 역시 실행 아이템 모양으로 정규화 되어 있습니다. 그런데 인벤토리가 부족해 이 실행 아이템을 획득하지 못하면 퀘스트를 클리어 했지만 배 컨텐츠가 언락되지 않는 상황이 일어날 수 있습니다. 때문에 인벤토리가 가득 차 실행 아이템을 획득하지 못하는 상황이 발생할 때 동작을 정의해야 하는 일이 일어난 것이었습니다. 근본적으로 이는 인벤토리 크기에 제한이 없거나 그 제한이 느슨할 때만 사용할 수 있습니다. 만약 인벤토리 최대 크기에 강한 제약이 있으면서도 실행 아이템을 도입했다면 이는 서로 맞지 않는 규칙을 동시에 사용하려고 하는 시도로써 어느 한 쪽을 포기하지 않는 이상 영원히 이상한 상황이 발생할 겁니다. 하지만 이미 인벤토리는 인벤토리대로 최대 크기에 강한 제약이 있고 실행 아이템은 실행 아이템대로 존재하는 불행한 상황이라면 인벤토리 최대 한도보다 더 많은 아이템을 받을 때 처리에 소개한 방식으로 우회할 수 있습니다.
실행 아이템은 근본적으로 그 역할에 실패하지 않을 것을 전재로 만든 것입니다. 엔지니어들이 사용하는 표현을 함부로 사용하는 것을 좋아하지 않지만 굳이 말하자면 실행 결과를 반환하지 않는 함수와 비슷합니다. 이들의 실행 결과를 확인하지 않는 이유는 그럴 필요가 없는 모양으로 동작하기 때문입니다. 인벤토리 크기에 제한이 없기 때문에 실행 아이템의 획득에 실패하는 상황은 없습니다. 또 실행 아이템이 반드시 인벤토리에 들어올 수 있기 때문에 실행 아이템에 데이터 모양으로 기입된 동작은 항상 실행됩니다. 보상 데이터 집행 실수로 이미 언락 된 컨텐츠를 언락하는 실행 아이템을 또 다시 지급하려 할 수는 있습니다만, 이 때는 이미 컨텐츠가 열려 있으므로 아무 것도 하지 않고 인벤토리로부터 실행 아이템을 제거하기만 하면 됩니다. 실행 아이템은 이렇게 그 실행에 실패하지 않을 것을 전제로 만들어졌기 때문에 실행 아이템을 처리하는 여러 로직, 아이템 획득, 실행, 제거 등의 과정에 실패가 일어날 것을 가정하는 순간 문제는 극도로 복잡해지고 게임디자이너 수준에서 그 동작을 정의하기 극히 어려운 문제가 됩니다. 이 글 제목인 ‘실행 아이템의 실패 동작’는 사실 실패 동작 정의가 필요한 것이 아니라 실패 처리를 정의해야 하는 요구사항이 우리들에게 도달한 상황 자체가 문제이고 실패할 때 동작을 고안하기 이전에 왜 이 요구사항이 나타났는지를 생각해 봐야 하는 상황입니다. 이를 눈치 채지 못하면 처음부터 게임디자이너가 정의하기 대단히 어려운 상황을 게임디자이너가 고통 받으며 정의하고 이 정의는 거의 항상 무조건 기술적인 현황과 맞지 않아 고통스러운 이터레이션으 수반합니다. 그럴 필요가 없습니다.
반면 실행 아이템 뿐 아니라 어떤 시도에 따른 실패 처리를 미리 고려해야만 하는 상황도 있습니다. 주로 고객이 능동적으로 어떤 시도를 할 때입니다. 고객이 경험치 아이템을 사용해 특정 캐릭터에게 경험치를 몰빵해 레벨을 올리려고 합니다. 그런데 그 캐릭터는 이미 최대 레벨에 도달해 있어 경험치를 더 이상 받지 못하는 상황일 수 있습니다. 인터페이스를 통해 이런 시도가 일어나지 않도록 하는 것이 기본이지만 어쨌든 이런 시도가 일어났다면 경험치를 더 받을 수 없는 캐릭터에게 경험치를 부여하려고 했고 경험치 부여에 실패할테니 이에 따른 처리는 필요합니다. 일단 고객이 능동적으로 시도한 다음 실패한 결과를 보여줄 수도 있고 애초에 그런 시도를 할 수 없도록 인터페이스를 고안할 수도 있습니다. 어느 쪽이든 내부적으로는 이 시도가 실패할 거라는 사실을 알기 위해, 아니면 이 시도가 실패했다는 사실을 고객에게 전달하기 위해 실패는 일어나야 합니다. 여기서 핵심은 고객이 능동적으로 시도한 행위에 대해서는 명시적인 실패 동작을 설계해야 한다는 점입니다. 반면 실행 아이템은 주로 아이템의 관점에서 능동적인 동작이 일어납니다. 동일하게 고객 관점에서 보면 실행 아이템은 고객이 능동적으로 어떤 동작을 시도한 상황이 아닙니다. 고객이 시도하지도 않은 동작은 실패할 수 없고 실패해서도 안됩니다. 메인 퀘스트를 클리어 한 다음 획득한 실행 아이템은 반드시 배 컨텐츠를 언락 한 다음 사라져야 합니다. 또한 내부적으로 어떤 이유에 의해 실패한다 하더라도 이를 고객에게 노출해서도 안됩니다. 고객이 아무 것도 하지 않았는데 ‘배 컨텐츠 언락에 실패했습니다’라고 말해 봐야 고객이 할 수 있는 일은 아무 것도 없기 때문입니다.
실행 아이템의 실패 동작을 고안하는 요구사항을 처리하기 어려운 이유는 실행 아이템은 고객 입장에서 이 아이템이 수행하게 만드는 동작을 능동적으로 요구하지 않아 실패해서는 안되기 때문입니다. 그래서 인벤토리 설계 단계에서부터 실행 아이템이 반드시 획득되도록 인벤토리 크기 제한이 없거나 대단히 느슨한 모양이어야 하며 그 실행 역시 실패해서는 안됩니다. 어떤 기술적 이유로 실패하지 않기가 불가능할 수도 있습니다. 그렇더라도 고객 눈에 띄지 않도록 조용히 처리해 고객이 눈치 채기 전에 반드시 성공한 상태에 도달해야 합니다. 그래서 실행 아이템의 실패 동작은 게임디자인에서 그 동작을 정의할 문제가 아닙니다. 그래서 게임디자인 입장에서 실행 아이템의 실패 동작을 정의하는 일이 아주 어려운 것입니다.