인터랙션 오브젝트는 어쩌면 통합이 능사가 아닐지 모른다
지금까지 비슷한 기능을 하는 여러 장치를 한 가지 시스템으로 통합하거나 처음부터 그렇게 설계해 왔는데 어쩌면 그게 늘 옳은 방법이 아닐지도 모르겠습니다.

2년 전 어느 여름날 갑자기 생각나서 인터랙션 오브젝트 설계 (1), 인터랙션 오브젝트 설계 (2), 인터랙션 오브젝트 설계 (3)을 작성한 적이 있습니다. 여러 회사마다 MMO 게임에 비슷한 역할을 하는 요구사항을 각기 다른 이름으로 정의하곤 하는데 여튼 핵심은 인게임에서 플레이어가 이 물체에 인터랙션을 하면 그 결과로 뭔가 또 다른 사건이 일어나고 설정에 따라 이 인터랙션과 이로 인한 사건이 다른 플레이어에게 동기화 되거나 동기화 되지 않거나를 선택할 수 있는 것입니다. 저 글들을 작성할 때는 한참 모바일로 출시된 디아블로 이모탈을 플레이 하고 있었는데 이 게임에서는 닫힌 문을 조작해서 열거나 보물상자 뚜껑을 열어 아이템을 먹고 또 독서대에 놓인 책을 펼치면 책 내용이 음성으로 재생되기도 합니다.
이런 물체들은 게임 전체에 걸쳐 다양한 모습으로 나타나지만 핵심은 인터랙션 가능한 상태로 세계에 나타났다가 플레이어가 다가가 인터랙션을 하고 인터랙션에 성공하면 상태가 변하며 미리 정해진 행동을 한 다음 다시 인터랙션 가능한 상태가 되거나 사라지는 등의 서로 다른 행동을 통해 인터랙션을 마무리하는 동작으로 정규화할 수 있다는 점입니다. 처음에는 근본적으로 인게임에 등장하는 여러 물체가 서로 다른 동작을 요구하지만 결국 이들의 동작을 정규화 해 보면 에셋과 인터랙션 규칙이 다를 뿐 서로 모두 똑같은 물체이기에 이들을 한 가지 요구사항으로 개발한 다음 계속해서 돌려 쓰면 된다고 생각하고 요구사항을 만들어 왔습니다. 최근에도 서로 다른 시점에 다른 요구사항에 기반해 개발된 여러 인터랙션 오브젝트처럼 보이는 물체들을 한 가지 확장성 있는 규칙에 기반해 통합하는 일에 관여한 적이 있는데 당연한 흐름이라고 생각했습니다.
하지만 어떻게 이렇게 빨리 만들었나요?를 작성할 때부터 이런 저런 생각을 해 보다가 어쩌면 이런 요구사항을 통합하는 일은 엔지니어 수준의 일일 뿐 게임디자인 입장에서의 일이 아닐 수 있고 어쩌면 저는 일을 더 복잡하게 만드는데 기여해 오고 있었을 뿐이 아니었을까 하는 의심을 해 보았습니다. 세계에는 여러 가지 인터랙션을 할 수 있는 물체가 있습니다. 가령 베어 목재를 얻을 수 있는 나무가 있고 뚜껑을 열어 아이템을 얻을 수 있는 보물상자가 있으며 여닫을 수 있는 문도 있습니다. 만약 어떤 게임을 만들지 확실하지 않은 상태에서 일단 눈 앞에 닥친 플레이시나리오를 달성하기 위해 시야가 좁은 요구사항을 만들다 보면 이들 각각을 서로 다른 시점에 서로 다른 모양의 요구사항으로 젝성해 엔지니어들에게 개발을 요청할 수 있습니다. 가령 맨 처음 던전을 만들고 던전 끝에서 던전 보상을 보물상자를 통해 줘야 하는 플레이시나리오를 좁은 시야에서 빨리 만들어야 하는 상황이라면 인터랙션, 캐스팅, 인터랙션 완료, 보물상자가 뚜껑이 열린 상태로 변함, 아이템 드랍 같은 최소한의 동작으로 구성된 요구사항을 작성하게 될 겁니다. 그리고 이건 처음부터 보물상자 전용으로 사용될 기능임을 가정해 요구사항을 작성하고 또 이를 코드로 옮기는 엔지니어 입장에서도 이보다 넓은 시야를 고려하지 않을 가능성이 높습니다. 게다가 이 상황에서 누군가 이보다 넓은 시야의 상황을 고려하려 한다 하더라도 개발 초반 경영진에게 빨리 그럴듯한 플레이어블을 보여 줘야 하는 상황에서 시야를 넓히는 행동은 그리 올바르지 않을 수 있습니다. 그렇게 보물상자가 던전 끝에 들어가고 이는 매우 잘 동작해 이후 던전에 계속해서 사용됩니다.
그리고 시간이 지나 이번에는 필드에 서 있는 나무에 도끼질을 해 나무를 쓰러뜨려 목재를 얻는 플레이시나리오를 달성해야 하는 상황이 생깁니다. 이번에도 더 넓은 시야로 요구사항을 조망하기 보다는 짧은 제한시간 안에 의미 있는 플레이어블을 제시해야 하는 상황이어서 게임디자이너는 나무에 집중한 요구사항을 작성합니다. 나무가 서 있고 플레이어가 나무에 인터랙션을 하면 없던 도끼가 나타나 나무에 도끼질을 하는 애니메이션이 재생되는데 이 과정 전체를 캐스팅으로 정의해 캐스팅 도중 이동, 피격, 스킬사용 등으로 캐스팅이 중단되면 캐스팅을 처음부터 다시 해야 합니다. 캐스팅을 마치면 목재를 얻을 수 있고 나무가 가지고 있는 목재가 모두 소진되고 나면 나무는 쓰러져 사라지며 나무 밑둥만 남게 됩니다. 시간이 지나면 밑둥에서 나무가 다시 생기고 똑같은 인터랙션을 반복할 수 있습니다.
사실 이 시나리오는 앞서 설명한 보물상자와 굉장히 비슷합니다. 일정 거리 안에 들어가 인터랙션을 시작하고 인터랙션에 캐스팅이 있으며 캐스팅이 끝나면 상태가 바뀌고 뭔가의 행동을 합니다. 보물상자는 뚜껑이 열린 상태로 바뀐 다음 아이템을 드랍하고 나무는 자신이 가지고 있는 목재가 남아 있으면 상태가 변하지 않은 채 목재 아이템을 드랍하고 자신이 가지고 있는 목재가 더이상 남아 있지 않으면 쓰러져 사라지는 애니메이션을 재생한 다음 나무 밑둥만 남은 상태가 됩니다. 보물상자와 비교해 남은 아이템에 따라 동작이 달라지는 차이가 있지만 실은 거의 비슷한 동작입니다. 하지만 이를 보물상자와 서로 다른 시점에, 플레이어블을 빨리 뽑아야 하는 상황에서, 게임디자이너가 좁은 시야에 기반해 요구사항을 작성하고, 이 요구사항을 받은 엔지니어 역시 이전에 개발한 다른 기능을 감안하지 않고 좁은 시야로 요구사항을 코드로 옮기다 보면 이제 게임 상에는 거의 비슷한 동작을 하지만 서로 완전히 달리 작성된 보물상자와 나무가 공존하게 됩니다.
이런 상황이 몇 번만 더 일어나면 게임에는 클릭하면 내용을 읽어주는 책, 클릭하면 파괴되는 바리케이트, 클릭하면 캐스팅 후 부가효과를 주는 신단, 클릭하면 거대한 소리를 내며 3초에 걸쳐 열리는 거대한 문, 스위치를 당기면 떨어지는 거대한 도개교 같은 여러 가지 물건들이 나타나지만 이들 각각이 서로 다른 시점에 서로 다른 사람들에 의해 개발되어 사로 다른 설정 방법, 서로 다른 예외 처리, 서로 다른 동기화 방법에 기반해 제작되어 이들 중 어느 하나에 발생한 문제 하나를 해결했지만 나머지 모두에는 똑같은 문제가 일어나는 상황이 쉽게 발생합니다. 가령 보물상자를 클릭하면 뚜껑이 그냥 띡 열리는 모습이 썩 아름답지 않다고 생각한 누군가가 보물상자를 클릭하면 보물상자 앞의 지정된 위치까지 걸어서 이동한 다음 이 자리에서 보물상자를 여는 애니메이션을 재생해 여기에 딱 맞게 보물상자 뚜껑이 열리고 뚜껑이 열리면 그 안에서 아이템이 드랍되도록 만들고 싶을 수 있습니다. 그래서 이번에도 좁은 시야에 기반해 요구사항을 작성해 이 기능을 개발하면 이제 보물상자는 분명 멋지게 동작하겠지만 어떤 사람들은 이 기능이 보물상자와 비슷하게 생긴 나무, 문, 책, 신단에서도 똑같이 동작할 거라고 쉽게 예상할 수도 있습니다. 그래서 각각의 물체에 맞는 플레이어 애니메이션 에셋을 제작했지만 이 기능은 오직 보물상자에만 개발되어 있어 나머지 물체에는 에셋을 적용할 방법이 아예 없다는 사실을 깨닫고 실망할 수도 있습니다. 처음으로 돌아가 이런 상황이 일어나다 보면 경험이 있는 누군가는 처음으로 보물상자를 개발하려 할 때 앞으로 이 보물상자와 비슷한 여러 가지 물체가 게임에 등장할 예정이니 이를 감안해 미래의 요구사항에 대응할 수 있는 구조를 어느 정도 미리 갖춰 두려고 할 겁니다. 하지만 앞서 설명한 대로 보통 이런 상황은 짧은 시간 안에 플레이어블을 도출해야 하는 상황일 때가 많아 이런 넓은 시야에 의한 요구사항을 작성하거나 그런 요구사항을 구현하기에 자원이 충분하지 않을 때가 많습니다.
또한 이런 정규화 해 보면 서로 비슷비슷한 요구사항들을 한 가지 통합된 요구사항을 만들다 보면 이들 각각이 별도의 물체로 만들어져 있을 때는 훨씬 이해하기 쉬웠던 시스템이나 데이터구조가 통합된 다음에는 훨씬 더 복잡해져 일반적인 지능을 가진 우리들이 이해하기 더 어려운 모양으로 변할 수도 있습니다. 가령 보상을 한 번만 드랍하는 보물상자와 보상을 여러 차례 드랍하는 나무는 사실 이 횟수에 차이가 있고 또 횟수에 따라 상태가 조금 달리 변할 뿐 사실 똑같은 물체라고 해석할 수도 있지만 누군가는 보물상자에 나무에서만 사용하는 횟수를 입력해 보상을 여러 번 토해내는 이상한 보물상자를 만들 수도 있는데 만약 보물상자가 아예 보물상자 역할만 하는 독립된 물체로 개발되었을 때는 결코 일어날 리 없는 실수입니다. 이런 생각을 하다가 어떻게 이렇게 빨리 만들었나요?의 사건을 겪으며 어쩌면 이런 비슷비슷한 시스템을 통합해 단일 규칙에 의해 모든 인터랙션 오브젝트가 동작하게 만드는 일을 당연하게 생각하고 프로젝트에 이런 요구사항이 나타날 때 이를 당연하게 받아들여 이들이 통합된 상태에서 데이터의 통합에 따른 동작을 정의하기를 이상하지 않게 여겼지만 마음 한편으로는 어쩌면 이들을 게임디자인 수준에서는 통합하지 않고 각기 서로 독립적으로 동작하는 물체로 유지하되 엔지니어 수준에서는 서로 통합할 수 있는 영역을 통합하는 것이 올바를 수도 있겠다는 생각을 하게 되었습니다.
가령 나무나 보물상자는 서로 겉모양이 다르기는 하지만 일단 플레이어가 일정 범위까지 다가가면 인터랙션 가능해지고 이 상태에서 인터랙션을 시작한다는 시나리오가 동일한데 이들을 제각각 개발했을 때는 플레이어와 물체 사이의 거리를 판정하는 기준이 물체에 따라 서로 다른 방식으로 개발되었을 수도 있습니다. 누군가는 물체가 커질 경우를 대비해 물체에 외접하는 원기둥을 기준으로 거리를 측정하도록 했을 수 있고 또 다른 누군가는 물체가 커질 리 없다고 생각해 물체의 중점으로부터 거리를 측정하도록 했을 수 있습니다. 이런 차이들은 엔지니어 수준에서 통합하고 게임디자인 관점에서는 여전히 정확히 필요한 정보만 입력하면 동작하는 보물상자, 또 정확히 필요한 정보만 입력하면 동작하는 나무가 별도로 존재하는 편이 어쩌면 더 나을 수도 있겠다는 생각을 해봅니다.
한번은 이렇게 서로 다른 시점에 개발된 서로 다른 물체들의 다양한 기능을 정규화 할 때 서로 거의 비슷한 기능의 단일 기능으로 이들 모두를 처리할 수 있음을 깨닫고 이들을 통합하려는 시도가 일어났고 이 시도에 대응한 적이 있었습니다. 앞서 이런 시도가 게임디자이너 관점에서 어쩌면 작업을 더 어렵고 복잡하게 만들 수도 있겠다는 생각을 해 보기는 했지만 아직 그건 제 생각일 뿐이었고 이를 다른 사람들에게 말하거나 다른 사람들을 설득하려고 시도할 만큼 생각을 온전히 정립한 상태도 아니었기에 일단 이번 프로젝트에서는 이전의 익숙한 습관 그대로 서로 다른 물체들을 정규화할 때 거의 같은 기능을 수행하는 한 가지 기능의 다양한 옵션 모양으로 통합하면서 일어나는 몇몇 동작을 정의합니다. 가령 앞서 말했던 여러 번 인터랙션 할 수 있는 나무에 인터랙션 횟수를 기입해야 하지만 이 횟수가 보물상자에 기입되면 보물상자가 이상한 동작을 할 텐데 이게 올바른지, 아니면 이런 예외를 처리하는 다른 규칙이 필요한지에 대한 질문에 답하기도 했습니다. 이 질문에는 보물상자에 실수로 나무에서만 사용하는 횟수를 입력하면 보물상자는 그 횟수의 동작에 맞춰 인게임에서 여러 번 열 수 있는 오동작을 수행하는 것이 올바르며 이는 실수이고 이는 데이터 관점에서 바로잡아야 하는 문제로 정의합니다. 사실 이들 모두가 한 가지 기능으로 통합되어 있다면 이런 동작을 허용해 전체 기능이 허용하는 범위 안에서 창의적인 물체를 만들어내 게임에 재미 있는 상황을 연출할 수 있는 가능성이 있는 것은 사실입니다. 그런데 서로 다른 물체에 따라 서로 다른 옵션을 정확히 입력해야 하고 이 과정에 실수하면 여러 번 열 수 있는 보물상자와 같은 어처구니 없는 동작을 유발할 수 있다는 점에서 과연 이런 의사결정이 올바른지는 좀 더 고민해볼 여지가 있습니다.
한편 이렇게 여러 물체의 기능을 통합하는 과정에서 일어나는 여러 상황에 따른 동작을 정의하다가 이전에는 그리 중요하지 않았던 한 가지 상황이 대두됩니다. 통합 이전 보물상자는 뚜껑이 닫힌 채로 나타나 가까이 다가가 인터랙션을 하면 보물상자 뚜껑이 열리고 아이템을 획득할 수 있었습니다. 한 번 뚜껑이 열린 보물상자는 계속해서 뚜껑이 열린 상태로 그 자리에 남아 있어 멀티플레이 상황에서 다른 사람들이 같은 보물상자를 볼 때 이미 뚜껑이 열려 있기 때문에 이미 누군가 아이템을 획득했음을 알 수 있습니다. 또한 통합 이전의 나무는 나무 모양으로 나타나 같은 방법으로 인터랙션을 통해 도끼질을 하면 목재 아이템을 드랍합니다. 다만 나무가 목재를 여전히 가지고 있다면 계속해서 도끼질 할 수 있고 나무가 더 이상 목재를 가지고 있지 않으면 나무는 쓰러지는 애니메이션을 재생하고 나무 밑둥을 남긴 채 사라집니다. 통합 이전의 바리케이트 역시 비슷한 방식으로 동작입니다. 바리케이트에 다가가 인터랙션을 하면 바리케이트가 무너지고 바리케이트가 막고 있던 길을 지나다닐 수 있게 되는데 바리케이트는 무너진 다음 그 자리에 남아 있는 대신 사라졌습니다. 사실 바리케이트 역시 부서진 상태로 그 자리에 남아 있도록 할 수 있었지만 보물상자나 나무와는 약간 다른 문제가 있었는데 보물상자와 나무는 뚜껑이 열리거나 쓰러질 때 애니메이션을 재생하더라도 그리 어색해 보이지 않았습니다. 그런데 바리게이트는 파괴될 때 애니메이션을 통해 파괴되면 모든 바리케이트가 항상 똑같은 모양으로 파괴되고 파괴된 다음에는 항상 똑같은 모양의 잔해를 남기므로 어색해 보일 수 있었습니다.
게임에 따라 이런 어색함을 줄이거나 없애기 위해 바리케이트를 파괴하면 일단 애니메이션을 통해 파괴되지만 파리케이트의 각 구성물이 바닥에 떨어지며 애니메이션이 끝나고 나면 이들 각각을 랙돌로 바꿔 플레이어가 걷어 차고 다닐 수 있게 만들었습니다. 그럼 바리케이트가 파괴될 때는 적당히 애니메이션에 의해 부서지는 것처럼 보이지만 바닥에 떨어진 잔해는 물리엔진에 의해 자기들끼리 부딪쳐 튕겨나가기도 하고 또 플레이어가 이 위를 지나가면 플레이어와 부딪쳐 튕겨나가 바닥에 남은 잔해가 이리 저리 예상하지 않은 위치로 돌아다니며 다른 모습을 만들어 바리케이트 여러 개를 연달아 파괴하더라도 이들의 잔해가 모두 다른 모양이 되어 어색하지 않은 형태가 됩니다. 만약 이 기능이 바리케이트에 한해 사용 가능하고 나머지 물체들은 이런 기능이 없었다면 더 이상 문제가 일어나지도, 복잡해지지도 않았겠지만 이런 기능을 하는 여러 물체들을 정규화 해 한 가지 기능을 통합하려고 보니 문제가 생깁니다. 바리케이트는 파괴되는 물체이기도 하지만 파괴되지 않은 상태일 때는 길을 가로막아 더 이상 지나갈 수 없도록 하는 역할 역시 담당하고 있습니다. 간단히 플레이어를 가로막아 지나갈 수 없게 만들어야 하는 목적만을 달성하려 한다면 클라이언트에서 바리케이트와 플레이어의 충돌을 감지해 플레이어를 지나가지 못하도록 하는 수준으로도 말이 되는 플레이를 만들 수 있습니다. 그런데 만약 이 상황에서 바리케이트 건너편에 몬스터들이 이 쪽을 바라보고 있다가 바리케이트가 파괴되는 순간 플레이어를 향해 공격해 오도록 해야 한다면 어떨까요? 또 원활한 이동 동기화를 위해 플레이어의 이동 조작을 꽤 강력하게 예측하는 상황에서 오직 클라이언트에서만 보이는 바리케이트가 길을 막고 있지만 이동 예측을 수행하는 서버는 클라이언트에서 플레이어가 바리케이트에 걸렸다는 사실을 아직 모른 채 플레이어가 바리케이트 너머로 이동해 버렸다고 판정해버리면 어떤 일이 일어날까요?
이런 문제들을 해결하기 위해 내비게이션 메시라는 방법을 사용합니다. 레벨을 제작한 다음 어느 한 지점을 선택한 다음 그 지점을 기준으로 이동 가능한 영역을 계산해 각각의 영역을 서로 연결된 메시 모양으로 나타낸 다음 이 데이터를 저장했다가 나중에 플레이어의 이동 동기화를 위한 이동 예측, 몬스터들의 이동 등에 활용하는 것입니다. 플레이어가 특정 방향으로 이동을 시작하면 이전에는 클라이언트에서 그 방향으로 이동 가능한지, 충돌할 물체는 없는지 검사했다면 이제는 서버가 그 방향의 내비게이션 메시로 이동 가능한지 검사한 다음 이동 가능하면 그 방향으로 이동을 승인하는 방식으로 동작합니다. 이 때 서버를 거쳐 이동이 확정되므로 조작이 답답하게 느껴질 수 있기 때문에 일단 클라이언트에서 이동을 수행한 다음 같은 이동을 서버가 계산한 결과와 비교해 이들 사이의 차이를 보정하는 방식으로 동작하는데 종종 캐릭터가 갑자기 다른 지점으로 순간이동 하는 이유는 클라이언트에서 이동한 위치와 같은 입력에 의해 서버가 예측한 위치 사이에 차이가 너무 커 서버 기준으로 플레이어의 위치를 보정했기 때문입니다. 몬스터는 특히 완전히 서버에 의해 제어되기 때문에 몬스터 입장에서는 클라이언트에 자신들과 충돌할 수 있는 물체가 있다 하더라도 이들의 존재를 기본적으로는 알 수 없습니다. 하지만 서버는 내비게이션 메시를 통해 몬스터들, 그리고 플레이어들이 이동 가능한 모든 좌표에 대한 메시 정보를 가지고 있기에 이들이 클라이언트 상에서 이동 불가능한 위치로 이동하지 않도록 제어할 수 있습니다. 여기까지는 꽤 괜찮아 보이지만 만약 여닫을 수 있는 문, 길을 막고 있다가 인터랙션을 통해 파괴되는 바리케이트가 등장한다면 어떨까요?
이런 문, 바리케이트의 특징은 이동 제어가 동적으로 일어난다는 점입니다. 보물상자는 뚜껑이 열린 다음에도 그 자리에 계속해서 남아 있고 나무 역시 목재가 없어지면 쓰러지지만 그 자리에 나무 밑둥이 남아 있습니다. 그러면 처음 내비게이션 메시를 계산할 때 보물상자가 있는 자리, 나무가 서 있는 자리는 이동할 수 없는 영역으로 정의하면 됩니다. 보물상자가 열리더라도 여전히 보물상자는 그 자리에 있으며 나무 역시 나무 밑둥이 그 자리에 남아 있으니 이들의 상태가 바뀌더라도 이들의 자리는 영원히 이동할 수 없는 영역이어도 전혀 이상하지 않습니다. 플레이어는 나무 밑둥을 돌아서 이동해야 하고 몬스터 역시 뚜껑이 열린 보물상자를 피해서 이동합니다. 그런데 여닫을 수 있는 문과 파괴할 수 있는 바리케이트는 각각이 닫힌 상태일 때, 그리고 파괴되지 않은 상태일 때는 플레이어와 몬스터의 이동을 가로막아야 하지만 이들이 열리거나 파괴된 다음에는 이동을 더 이상 가로막지 않아야 합니다. 문이 열리면 열린 문을 통해 플레이어와 몬스터가 서로 오가거나 서로 공격을 주고 받을 수 있어야 하고 바리케이트가 파괴되면 이를 사이에 두고 있던 플레이어와 몬스터가 서로를 보고 공격할 수 있어야 합니다. 이전까지는 내비게이션 메시를 정적으로 한 번 생성한 다음 이 정보가 바뀌지 않는다는 가정 하에 플레이어와 몬스터들이 이동하면 됐지만 그 자리에 존재하며 길을 막고 있다가 이들이 사라지면 이동 가능해지는 물체가 나타나는 순간 내비게이션 메시의 일부는 동적으로 움직이기 시작해야 합니다. 문이 닫혀 있을 때는 문이 차지한 내비게이션 메시 영역이 끊겨 있지만 문이 열리면 이 메시가 이동 가능하게 바뀌어야 합니다.
이를 써 놓고 보면 당연하지만 이전까지는 내비게이션 메시가 정적으로 동작할 거라고 가정하고 설계한 여러 부분을 크게 고쳐야 하거나 내비게이션 메시의 일부가 변경되었음을 그 주변에 있는 모든 플레이어들에게 전달해야 해서 비용이 상당히 증가할 수 있습니다. 오직 서버에 의해 제어되는 몬스터는 그나마 상황이 나은 편입니다. 서버는 바리케이트가 파괴되며 이 물체가 차지하고 있던 내비게이션 메시 영역이 이동 가능한 상태가 되면 이 사실을 즉시 할 수 있기 때문에 바로 이어서 몬스터들이 AI에 의해 요청하는 플레이어를 향한 공격을 즉시 검증해 승인할 수 있습니다. 그 전까지는 바리케이트에 의해 플레이어까지 이동 가능한 경로가 막혀 있어 몬스터들이 AI에 의해 서버에게 플레이어를 공격하겠다고 요청하더라도 서버는 플레이어까지 이동 가능한 경로가 없으므로 이 공격 요청을 거절하고 몬스터들은 계속해서 플레이어들을 못 본 첫 행동하거나 공격을 시도하려고 했다가 계속 제자리에 멈춰 있는 행동을 반복하고 있을 테고 이는 그럭저럭 괜찮아 보입니다. 그런데 서버가 제어하지 않는 플레이어들은 문제가 있습니다. 플레이어들 역시 몬스터와 마찬가지로 바리케이트 너머에서 몬스터들을 공격하거나 몬스터들이 있는 영역으로 이동을 시도하려고 할텐데 이 때 클라이언트는 이들을 바리케이트 너머로 이동 시키려고 시도하지만 일단 바리케이트와 충돌에 막혀 이동이 불가능한 상태입니다. 같은 계산을 서버에서 수행해 보니 바리케이트가 파괴되지 않아 이 자리에 있는 내비게이션 메시가 여전히 이동 불가능한 상태이기 대문에 플레이어들의 이동 요청은 거절되고 클라이언트가 제안한 최종 위치를 수용하는 상태가 유지될 겁니다.
이 때 어느 플레이어가 바리케이트를 파괴하면 이 사실이 서버에 전달되는데 이 때 서버는 순간적으로 상당히 바쁘게 움직여야 합니다. 일단 바리케이트가 파괴되었으므로 이 물체가 점유하고 있던 내비게이션 메시가 이제 이동 가능한 영역으로 바뀌었음을 표시하고 이 다음부터 일어나는 이동 요청은 이 지점을 이동 가능한 상태로 계산한 결과를 반환합니다. 이 순간부터 몬스터들이 AI에 의해 플레이어를 공격하겠다고 요청하면 서버는 이제 이들 사이를 가로막고 있던 이동 불가능한 내비게이션 메시가 없으므로 이들의 공격 요청을 승인해 몬스터들이 플레이어 방향으로 달려오기 시작합니다. 그런데 이 시점까지 아직 플레이어들은 서버로부터 바리케이트가 점유하고 있던 내비게이션 메시가 이동 가능한 영역으로 바뀌었음을 아직 통보 받지 못한 상태일 수 있어 누군가 성격 급한 고객이 빠르게 조작한 플레이어는 분명 시각적으로는 바리케이트가 무너져 그 너머로 이동할 수 있을 거라고 생각하고 이동을 시도해 클라이언트에서는 이동이 승인되지만 같은 정보가 서버에서는 아직 승인되지 않아 무너진 바리케이트를 통과하지 못하고 원하지 않는 영역으로 순간이동 될 수 있습니다. 이런 문제를 최소화 하기 위해 서버는 동적으로 내비게이션 메시의 상태가 변경되면 이 사실을 모든 플레이어들에게 통보해 플레이어들이 이동을 시도할 때 클라이언트가 플레이어의 파괴된 바리케이트 너머로의 이동을 즉시 승인하게 만듭니다. 이 때 서버는 순간적으로 그 주변에 있는 여러 플레이어들에게 내비게이션 메시의 상태 변화를 통보해야 하므로 이런 자잘한 작업들의 시간 차이에 의한 오동작이 일어날 수 있고 또 이 시점에 서버가 갑자기 바빠져 버벅거릴 수도 있습니다.
하다못해 일방적으로 파괴되기만 하는 바리케이트만 해도 이렇게 복잡한데 만약 계속해서 상태를 바꿀 수 있는 문이 있고 플레이어와 몬스터 양쪽 모두가 문의 열린 상태에 따라 행동에 영향을 받아야 한다면 이 문제는 조금 더 골치 아파집니다. 시나리오 대부분이 동일하지만 플레이어가 문을 조작할 수 있다면 문을 열면 그 때 문이 점유한 내비게이션 메시가 이동 가능한 상태가 되어 앞서 설명한 모든 행동들이 가능해져야 하고 반대로 문을 닫으면 반대의 동작이 일어나야만 합니다. 이 때마다 서버는 내비게이션 메시의 상태에 따라 몬스터들의 공격 요청을 수락하거나 거절해야 하고 또 클라이언트에서 일어나는 플레이어들의 예측 이동 결과를 비교한 다음 그 결과를 승인하거나 되돌려야만 합니다. 이런 동작을 위해 문이 열리고 닫힐 때마다 계속해서 내비게이션 메시의 상태를 주변의 모든 플레이어들에게 통보해야 하기도 합니다. 퍼시스턴트 월드와 인스턴스 월드에 살펴본 것처럼 이렇게 상태가 바뀌고 그 상태를 모두에게 동기화 해야 하는 물체가 여러 플레이어들이 나타날 수 있는 장소에 있다면 상당한 오버헤드를 일으키게 되고 누군가는 이 상황에서 오동작을 경험할 가능성이 높아지며 서버는 계속해서 수많은 사람들에게 내비게이션 메시의 상태를 통보하기를 반복해야만 합니다. 그리고 여기에 앞부분에서 설명한 여러 인터랙션 오브젝트의 동작을 정규화 해 이들을 한 가지 동작으로 통합하려고 할 때 방금 전까지 설명한 여닫을 수 있는 문과 파괴할 수 있는 바리케이트 문제가 모든 인터랙션 오브젝트로 전파됩니다.
실은 현대에 경험해본 여러 게임은 그 역할을 마친 물체가 사라지는 동작을 더 많이 합니다. 가령 던전에서 만난 보물상자를 열어 아이템을 획득하면 보물상자는 사라지고 그 자리에는 바닥만 남습니다. 또 목재를 획득하고 남은 나무는 쓰러지며 밑둥을 남기지만 게임에 따라서는 그 밑둥에 다시 인터랙션 하면 그 밑둥 마저 제거하고 아무 것도 남기지 않을 수도 있습니다. 앞서 바리케이트는 파괴될 때 애니메이션을 통해 그 조각을 바닥에 떨어뜨리지만 바닥에 떨어진 조각 각각은 랙돌로 바뀌어 자기들끼리, 그리고 플레이어에 의해 충돌해 사방으로 튀어다니며 자연스러운 모습을 연출하지만 무한정 튕겨다니다가는 이를 실행하는 기계를 과열 시켜 프레임을 떨어뜨리기에 충분하므로 짧은 시간이 지나면 남은 조각 모두를 사라지게 만듭니다. 이렇게 하는 이유는 표면적으로는 그 역할을 마친 물체를 최대한 빨리 클라이언트와 서버로부터 제거해 성능을 유지하려는 것이지만 게임디자인 상의 이유도 있습니다. 현대에 가까워질수록 고객들은 주의력이 점점 약해져 상호작용을 마친 물체가 그 자리에 남아 있으면 그 물체가 여전히 상호작용을 요구할 거라고 착각하는 경향이 있어 보입니다. 가령 던전을 진행하던 도중 중간 보스가 있던 방에 보물상자가 있어 이를 열어 보상을 획득했는데 이 보물상자가 뚜껑이 열린 상태로 남아 있을 때 이전 같으면 뚜껑이 열린 보물 상자는 그 역할을 마쳤으므로 다음 방으로 넘어가면 되지만 상당수 고객들은 뚜껑이 열려 있긴 하지만 여전히 보물상자가 그 자리에 있으므로 이 보물상자와 어떤 인터랙션을 수행해야 한다고 반응해 그 자리에 머무르기도 합니다. 때문에 성능 상의 이유로도 역할이 끝난 물체를 게임으로부터 제거해야 하지만 게임디자인 측면의 이유로도 물체를 게임으로부터 제거해야 하기도 합니다.
서로 다른 여러 가지 인터랙션 오브젝트는 정규화 되어 한 시스템으로 통합되었고 여기에는 여닫을 수 있는 문이나 길을 막고 있는 바리케이트처럼 내비게이션 메시에 영향을 주는 물체들도 포함됩니다. 이들이 서로 통합되고 또 이전과 달리 보물상자나 나무 밑둥이 게임으로부터 완전히 사라질 수 있게 되면서 이전에는 내비게이션 메시에 의해 영향을 받지 않는다고 생각했던 물체들도 내비게이션 메시의 영향을 받아야만 하는 물체로 바뀝니다. 가령 중간 보스가 나타나는 방 가운데 있는 보물상자는 중간보스가 죽기 전에는 열리지 않습니다. 이 보물상자는 분명 시각적으로 자리를 차지하고 또 내비게이션 메시를 계산할 때 이 자리에 보물상자가 놓여 있으니 보물상자가 차지하는 자리의 메시는 이동 불가능하기에 아예 메시를 생성하지 않았을 겁니다. 그래서 플레이어와 몬스터 양쪽 모두 서로를 공격하거나 이동할 때 이 보물상자를 돌아서 이동했을 겁니다. 이제 중간보스가 쓰러지고 보물상자가 열려 보상을 획득하자 보물상자가 스르륵 사라질텐데 이 때부터 이상한 일이 벌어집니다. 만약 보물상자가 전통적인 방식으로 내비게이션 메시를 생성하지 않았다면 분명 시각적으로는 보물상자가 사라졌지만 실제로 보물상자가 있던 위치로 이동해 보려고 하면 결코 보물상자가 있던 위치로 이동할 수가 없습니다. 애초에 그 자리는 내비게이션 메시 상에서 이동할 수 있는 영역이 아니기 때문입니다. 만약 이 상황에서 몬스터가 출연하기라도 하면 몬스터들 역시 분명 아무것도 없는 보물상자가 있던 그 자리를 여전히 보물상자가 그 자리를 가로막고 있는 것처럼 그 자리를 피해서 이동하고 그 자리를 피해서 공격하는 어색한 동작을 하게 됩니다.
이전까지 서로 다른 물체가 서로 다른 요구사항에 기반해 서로 다른 시점에 개발되었을 때는 비록 비슷한 동작을 하는 여러 물체가 코드 상에 어지럽게 널려 있어 이들의 기능을 정규화한 다음 통합하고 싶은 충동을 느꼈을 테고 저 역시 그런 충동에 완전히 동의하며 그런 과정에 여러 번 참여했습니다. 그런데 그런 통합 과정을 거치며 이전에는 어느 한 물체에만 필요했던 기능이 통합된 기능 전체에도 영향을 끼치는 모양으로 변하며 일을 좀 더 복잡하게 만들거나 게임디자인 관점에서 필요 이상으로 비용이 높은 기능을 아무렇지도 않게 요구할 수 있을 여지를 만드는 것 같습니다. 가령 이 모든 기능이 통합되기 전까지 보물상자는 항상 그 자리에 있고 뚜껑을 연 다음에도 그 자리에 남아 있어 내비게이션 메시를 동적으로 제어하는 그 모든 비용을 지출할 필요가 없었습니다. 여닫히는 문, 길을 막는 바리케이트, 스위치를 당기면 떨어지는 도개교 정도가 동적으로 내비게이션 메시를 제어하는 물체들이며 이들을 조심스럽게 비용 통제 하에 사용하면 게임디자인 입장에서도 원하는 바를 달성할 수 있고 엔지니어 입장에서도 딱히 중요해 보이지 않는 동작에 과도한 비용을 사용하도록 만들지 않아도 되었을 수 있습니다. 그런데 이들 기능이 정규화되어 통합되면서 모든 물체가 이런 과도한 비용을 사용할 여지를 가지게 되었으며 특히 앞서 잠깐 설명한 현대에 가까워짐에 따라 고객들의 플레이 패턴이 바뀜에 따라 게임디자인 관점에서 이를 해결하기 위해 다른 게임의 동작을 복제하려는 단순한 요구사항이 통합된 인터랙션 오브젝트에서 모든 물체가 내비게이션 메시에 영향을 줄 수 있게 되면서 훨씬 더 비용이 높은 문제로 바뀐 것이 아닐가 하는 생각을 해 보았습니다.
여러 프로젝트에서 이런 기능을 바닥부터 설계할 때는 항상 처음부터 정규화된 모양에 기반해 미래에 확장될 수 있는 모양으로 설계했고 만약 중간에 참여해 이미 그렇게 만들어지지 않은 경우에도 이들을 통합해 한 가지 기능으로 재정의하곤 했으며 이런 행동이 당연하고 또 전혀 이상하다고 생각하지 않았습니다. 그 때는 당연히 모든 물체가 내비게이션 메시를 당연히 제어하고 심지어는 실시간으로 이 움직임을 클라이언트의 디버깅 모드에서 볼 수 있었어도 이게 얼마나 비용이 높은 구현의 결과인지 잘 인식하지 못해 왔습니다. 그러다가 최근 비슷한 일을 다시 겪으면서 이전에 당연하게 생각했던 여러 요구사항과 이에 대한 대응이 실은 생각보다 상당히 비용이 높은 구현의 결과라는 사실을 조금은 인식하게 되었습니다. 지금까지의 맥락에서 어쩌면 여태까지 당연하게 생각해 온 게임디자인 관점에서 비슷한 기능을 정규화 한 단일 기능을 설계하는 행동은 어쩌면 작업 난이도를 올리고 이전까지는 필요 없었을른지도 모르는 비용을 사용하게 만드는 역효과를 내고 있을지도 모른다는 생각을 해 봅니다. 어쩌면 적어도 게임디자인 관점에서는 이들을 각각의 기능에 대한 요구사항으로 정의해 필요한 데이터만 넣으면 동작하게 만들고 또 필요하지 않은 확장 기능은 아예 사용할 여지 조차 주지 않도록 만드는 편이 어떻게 이렇게 빨리 만들었나요?에 들은 설명처럼 우리들이 더 단순하게 기능을 개발해 더 빨리 게임을 만들어 나갈 수 있는 방법이 아닐까 싶기도 합니다. 미래에 다른 프로젝트에 참여한다면 이 생각을 좀 더 해보고 그에 따른 결과에 따라 행동해 봐야겠습니다.