Gamedec 개발팀에서 1년 반 째 프로그래머로 근무 중인 Przemysław는 디자인팀을 위해 게임플레이와 툴을 제작하는 역할을 맡고 있습니다. 덕분에 디자이너가 더 쉽게 일할 수 있는 솔루션이 만들어집니다. Przemysław는 여가 시간에는 최신 기술 동향에 대해 살펴보고 새로운 레고 블록 세트를 조립하는 등 창조적인 취미에 몰두합니다.
게임덱(Gamedec)은 쿼터뷰(아이소메트릭 뷰)를 채택한 싱글 플레이용 비전투형 사이버펑크 RPG입니다. 플레이어는 가상 세계에서 범죄를 해결하는 사립 탐정 게임덱(Gamedec)이 됩니다. 플레이어가 내린 결정에 따라 캐릭터의 특성이 달라지고 게임의 진행 방향에 영향을 주지만, 사건들은 딜레마로 가득하며 명쾌하게 해결되는 경우가 드뭅니다. 결국 플레이어의 결정이 모든 것을 좌우합니다.
게임덱은 방대하고 복잡한 대화와 결정에 따른 분기점을 토대로 진행되는 게임입니다. 한 가지 결정으로 문제 해결의 길이 열릴 수도 있지만, 다른 길이 막힐 수도 있습니다. 이렇게 복잡한 게임을 제작하려면 특별한 툴이 필요합니다. 언리얼 엔진과 함께 저희는 아티시를 사용했습니다. 아티시라는 하나의 일관적인 비주얼 툴로 게임 글 작성, 기획, 콘텐츠 관리를 모두 처리할 수 있습니다.
Anshar Studios 이미지 제공
게임덱 분기 경로의 한 가지 예입니다.
목표
게임덱 월드를 더 역동적으로 만들기 위해 디자이너는 풍부한 대화뿐 아니라 NPC의 움직임, 월드의 변화, 배경 음악 등도 잘 활용해야 합니다. 플레이어는 단순히 텍스트 블록을 클릭하는 것이 아니라 게임과 진정으로 인터랙션한다는 느낌을 가져야 합니다.
초반에 게임덱 팀에는 만만치 않은 문제가 있었습니다. 게임덱 팀은 플레이어의 선택에 따라 월드에 영향을 주기 위해 테크니컬 네임(technical name)이라는 아티시 오브젝트를 나타내는 독특한 시퀀스에 의존해야 했습니다.
이 접근법에는 몇 가지 문제점이 있었습니다. 레벨 블루프린트를 처음 보면 특정 테크니컬 네임이 표현하는 대화 부분이 어느 것인지, 해당 대화가 어디에서 호출되고 무엇을 하는지 알 수가 없었습니다. 이를 확인하려면 아티시를 열어서 테크니컬 네임이 이름이 있는 노드를 찾은 다음, 분기를 분석하여 게임에서 어떤 일이 발생해야 하는지를 알아야 했습니다. 또한, 아티시만으로 작업하는 팀원은 어떤 노드가 언리얼 엔진에서 동작을 트리거하는지도 확실히 몰랐습니다.
Anshar Studios 이미지 제공
대화 선택 시 그 응답으로 이벤트를 실행하는 첫 번째 접근법은 이와 같이 스위치를 기반으로 했습니다.
Anshar Studios 이미지 제공
게임덱 분기 경로의 한 가지 예입니다.
명백한 두 번째 문제도 있었습니다. 그것은 디자이너가 언리얼 엔진에서 이벤트를 트리거할 다른 노드를 선택하면 레벨 블루프린트에서 테크니컬 네임을 변경해야 한다는 점이었습니다. 게임 제작, 특히 정말 많은 대화와 인터랙션이 일어나는 게임 제작은 매우 반복적인 작업입니다. 여러 곳을 동시에 변경해야 하기 때문에 실수할 위험이 커지고 시간을 많이 할애하게 될 수 있습니다.
해결책
이러한 문제들을 극복할 수 있도록 아티시는 사용자의 함수를 수행하는 매우 편리한 메커니즘을 제공합니다. 인스트럭션 블록에 함수 호출을 삽입하면 위에서 언급한 팀이 마주했던 문제들이 사라집니다.
Anshar Studios 이미지 제공
인스트럭션 블록이 이 문제를 해결합니다.
문제에 대한 해결책은 인스트럭션 블록입니다. 이 기능의 첫 번째 장점은 지정된 활동이 언제 수행되는지를 디자이너가 정확히 안다는 점입니다. 인스트럭션 블록의 위치를 변경해도 언리얼 엔진에서는 변경할 필요가 없다는 점은 주목할 만합니다. 대화의 다른 지점에서 이미 정의된 함수를 호출하면 되기 때문입니다.
자체 함수 사용도 상당한 장점이 됩니다. 이제 게임플레이 프로그래머는 더 이상 블루프린트 레벨에서 어떤 동작도 정의할 필요가 없어졌습니다. 저희는 많은 함수를 생성해서, 대화를 생성하는 동안 아티시 레벨에서 게임을 더 쉽게 제어할 수 있게 만들었습니다.
예를 들어, NPC와 대화를 나누다가 대화에서 말하는 특정 위치로 가기를 바란다면, GoTo와 FollowBy라는 두 가지 인스트럭션을 사용합니다. 인스트럭션에 위치, 보행 속도 등의 필수 파라미터를 전달함으로써 해당 위치로 이동할 수 있습니다.
Anshar Studios 이미지 제공
선택한 대화로 호출되는 컷씬입니다.
구현
물론 아티시는 Locations_TheaterDoor가 어디에 있는지 Characters_Admin이 어떤 NPC인지 등은 전혀 모릅니다. 이는 언리얼 엔진에서 정의해야 합니다. 이러한 목적으로 저희는 액터를 시스템에 등록할 수 있는 컴포넌트를 생성했습니다.
Anshar Studios 이미지 제공
위에 보이는 극장 문을 Locations_TheaterDoor로 등록했습니다.
이 시스템은 복잡하지 않고 단순합니다. 레벨이 시작되면, 이 컴포넌트가 있는 모든 액터는 딕셔너리에 이 데이터가 저장된 오브젝트에 등록됩니다. 키는 지정된 식별자이고 값은 액터에 대한 레퍼런스입니다.
그렇다면 아티시와 UE4가 바인딩된 모습은 어떨까요? 그리고 이러한 함수들은 어떻게 작동할까요? 먼저, 저희 함수를 인스트럭션 블록에 넣으면, 아티시에서 언리얼 엔진에 데이터를 임포트하는 플러그인이 UserMethodProvider라는 인터페이스를 생성하며, 여기에는 아티시에서 사용되는 모든 함수 정의가 포함됩니다.
Anshar Studios 이미지 제공
이 목록은 생성된 인터페이스의 일부를 보여줍니다.
생성된 인터페이스에 사용 가능한 사용자 생성 함수 세트가 항상 포함되도록 파라미터와 함께 정의된 모든 인스트럭션이 포함된 아티시 플로 섹션을 만들었습니다. 이 섹션은 절대 실행되지는 않지만 익스포트는 되므로 설령 사용하지 않는다 하더라도 모든 함수가 이 인터페이스에 포함되어 있다는 것을 알 수 있습니다. 이를 통해 향후 문제를 피할 수 있습니다. 언리얼 엔진의 API 선언과 비슷하기도 합니다.
Anshar Studios 이미지 제공
사용할 수 있는 모든 함수 세트를 포함하는 플로 부분입니다.
언리얼 엔진용 Articy 플러그인에는 UAArticyFlowPlayer 클래스가 있습니다. 이 클래스는 대화 트리 속을 이동하고 대화 분기를 탐색할 수 있게 합니다. 이 클래스에는 위에서 설명한 인터페이스를 액터 또는 컴포넌트가 구현하는지 확인하는 함수가 있습니다. 기본적으로 이 작업을 수행합니다. 이제 UserMethodProvider 인터페이스를 구현하는 컴포넌트를 생성하여 함수의 동작을 정의할 수 있습니다.
게임덱의 경우 후속 기능이 계속 추가되면서 그 압박으로 인해 인터페이스가 훨씬 커졌기 때문에 인터페이스를 더 작게 나눠야 했습니다. 그래서 함수 그룹 하나씩만을 포함하는 더 작은 인터페이스를 여러 개 제작했습니다. 그런 다음, 기본 인터페이스를 구현하고 함수 실행을 해당 개체에 위임하는 표면적인 인터페이스를 만들었습니다. 이러한 방법으로 시스템을 더 작게 여러 개로 나누고 전체적으로 논리적인 무결성을 유지할 수 있었습니다.
또한, 여러 클래스를 등록하면 하나의 특정 이벤트에 대응할 수 있습니다. 저희는 같은 함수가 반복 실행되는 문제를 겪었습니다. 이는 트리의 횡단 행동이 가진 특이성 때문이었습니다. FlowPlayer는 특정 대화 블록을 실제로 실행하기 전에 가능한 모든 경로를 분석합니다. 이는 특정 분기로 진입할 수 있는지 결정하기 위해 충족해야 하는 조건과 관련이 있으므로 선택할 수 있는 옵션 목록을 표시합니다.
하지만, 아티시에는 이 문제를 도울 섀도 모드(Shadow Mode)라는 기능이 있습니다. 어느 분기를 선택할 수 있는지 분석할 때, 아티시는 이 특별한 (섀도) 모드 안에서 분석하는데, 이 모드는 변수와 게임플레이에는 영향을 주지 않습니다. 주어진 특정 노드를 통과하면 그때 섀도 모드에서 벗어나게 되며 비로소 함수가 실행됩니다. 이 부분에서 각별히 주의해야 합니다.
Anshar Studios 이미지 제공
문제
아티시에서 사용자가 생성한 함수를 사용할 때도 특정 문제가 발생합니다. 아티시에는 처음부터 바로 자체 함수의 구문을 검사하는 메커니즘이 없기 때문입니다. 디자이너에게는 사용한 함수가 존재하는지, 함수에 전달된 파라미터가 언리얼 엔진에서 구현된 것과 같은지에 대한 정보가 없습니다. 한 동안은 이 점이 문제였습니다.
저희는 아티시의 어떤 변경 사항이 일일 빌드 작업에 이슈를 발생시킨 것인지 몇 시간 동안 분석한 적도 여러 번 있었습니다.
단순히 함수 이름에 오타가 난 적도 있었고 인수 유형이나 인수 개수가 잘못되었거나 로그 분석으로 빠르게 파악할 수 있는 오류 문제가 발생했습니다. 한 번은 블록의 마지막 함수에서 세미콜론이 누락된 적도 있었죠. 이런 경우에는 보통 임포터가 함수 끝에 누락된 세미콜론을 붙이기 때문에 문제가 되지 않습니다. 이 경우 저희는 깜빡하고 함수에 세미 콜론을 넣지 않고 함수 뒤에 코멘트 블록을 추가했었습니다.
문제가 발생하는 인스트럭션의 예:
CallEvent("OpenHiddenRoom")// Open the secret room
이 문제는 로그를 분석해도 빠르게 파악할 수가 없었습니다. 그 이유는 오류가 완전히 다른 곳을 가리키고 있었기 때문입니다. 결국 오류를 찾으려면 적용한 변경 사항을 하나하나 모두 분석하고 코멘트를 만들어야 했습니다. 마지막 함수에 세미콜론을 추가하는 걸 잊고 코멘트 블록을 추가한 다음 플러그인을 추가하여 아티시에서 데이터를 임포트하자 엔진에 버그가 발생했습니다. 그러자 반환 유형이 void에서 object로 변경되고, 그 결과로 컴파일 오류가 발생한 것이었습니다.
이날 저희는 이러한 이슈가 반복되는 것을 방지 또는 최소화하기로 결정했습니다. 안타깝게도, 아티시에서는 사용자가 생성한 함수의 헤더를 정의할 수가 없습니다. 사실상 디자이너가 구문을 확인할 수가 없으므로 실수가 발생할 여지가 있는 것입니다.
하지만, 아티시에서 자체 플러그인을 제작할 수는 있습니다. 그래서 저희는 모든 인스트럭션 블록을 분석하여 함수를 찾는 플러그인을 만든 다음, 해당되는 정의와 호환되는지 확인해 봤습니다. 아티시를 활발하게 사용하던 모든 팀원에게 이 플러그인을 설치해주자, 그때부터 일일 빌드에서 아까와 같은 문제가 더 이상 발생하지 않았습니다.
Anshar Studios 이미지 제공
결론
게임 개발 과정에서는 모든 결정이 중요합니다. 어떤 소프트웨어, 툴 체인, 소프트웨어 아키텍처를 선택하는지와 같이 말입니다. 아티시를 인터랙션 생성 툴로 선택하고 이를 사용자가 만든 함수와 저희의 자체 플러그인으로 확장한 것은 옳은 선택이었습니다. 언리얼 엔진용 에디터 유틸리티 위젯을 제작하는 기능 덕분에 아티시와 UE4 사이의 인터랙션을 디버깅하는 툴을 빨리 개발할 수 있었습니다. 이것은 게임 개발에 중대한 역할을 했습니다. 시기적절하게 작업을 간소화하는 결정을 내림으로써 인터랙션의 빠른 반복 작업이라는 가시적인 성과를 거뒀으며, 프로그래머의 개입 없이 플레이어를 이끌 신속한 프로토타입도 제작할 수 있었습니다.
블루프린트로 게임 프로토타입을 빨리 제작할 수 있다는 점과 아티시에서 생성된 대화로 직접 게임플레이 흐름을 제어할 수 있다는 점이 결합하자 게임덱과 같은 선택 기반의 게임을 제작하는 데 있어 놀라운 장점을 발휘했습니다. 이를 통해 디자이너는 프로젝트에 적용한 변경 사항이 스토리를 제대로 반영하는지를 빠르게 테스트할 수 있었습니다.
디자인 측면에서 퀘스트 디자이너는 프로그래머나 그래픽 디자이너와 같은 팀원의 도움 없이도 언리얼 엔진에서 인터랙션의 뼈대를 만들 수 있습니다. 퀘스트 디자이너가 스스로 해보고 여러 가지를 시도한 후 반복 작업할 수 있었습니다. 대단한 이점으로서 덕분에 여러 명이 의사소통하느라 소모될 수 있는 시간을 상당히 줄일 수 있었습니다. 아티시를 언리얼 엔진과 함께 사용하면 게임덱 개발에 가장 적합한 방식으로 요구에 맞춰 조정할 수 있는 다양한 툴과 메커니즘이 제공됩니다.
지금 언리얼 엔진을 다운로드하세요!
세계에서 가장 개방적이고 진보된 창작 툴을 받아보세요.
모든 기능과 무료 소스 코드 액세스를 제공하는 언리얼 엔진은 제작에 바로 사용할 수 있습니다.