Andrey Dyakov는 곧 출시될 게임 Atomic Heart의 개발사인 Mundfish의 CTO입니다. Andrey Dyakov는 저명한 스튜디오에서 언리얼 엔진 3와 언리얼 엔진 4로 AAA급 게임을 개발하며 10년 이상 경력을 쌓았습니다.
안녕하세요. 저는 곧 출시될 아토믹 하트(Atomic Heart)의 개발사인 문드피시(Mundfish)서 CTO를 맡고 있는 안드레이 디야코프(Andrey Dyakov)입니다. 이 기술 블로그에서는 저희가 게임 개발에 사용한 기술에 대해 다루면서, 언리얼의 게임플레이 어빌리티 시스템(Gameplay Ability System, GAS)을 활용하여 개발 프로세스를 변경한 방법에 초점을 맞출 것입니다.
이 게시물은 매뉴얼이 아니며 저희의 경험을 담고 있습니다. 하지만 GAS에 익숙하고 이를 자신의 프로젝트에 활용해본 개발자라면 도움이 될 수 있습니다.
최근에는 GAS에 대한 정보가 많이 나와 있지만 저희는 시스템에 대한 문서나 지원이 많지 않았던 초기에 저희가 했던 연구에 대해 말씀드리고자 합니다.
2018년, 저희는 플레이어의 액션을 구분하고 실행 규칙을 정의하는 자체 액션 필터 시스템을 갖추고 있었고 여기에 대체로 만족한 상태였습니다. 이를 활용해 다른 액션 도중에 특정 플레이어 액션을 시작(예: 웅크린 도중 점프하기)하거나 시작을 차단할 수 있었습니다.
하지만 이 시스템은 저희에게 필요한 여러 서브시스템 가운데 하나에 불과했고 다음과 같은 여러 핵심 개발 문제를 해결해야 했습니다.
충전된 근접 무기의 산성, 전기, 화염 및 원거리 무기 탄환에 의한 특수 대미지 처리
단일 캐릭터에게 적용된 여러 대미지 유형의 축적 및 처리
플레이어 캐릭터의 특수 능력 구현 및 실행 흐름 제어
온라인 리플리케이션 구현(아토믹 하트를 싱글 플레이어 게임으로 최종 결정하기 전 고려한 사항)
이 모든 문제를 해결할 유일한 시스템은 언리얼의 게임플레이 어빌리티 시스템이었습니다. 저는 몇 주간 한 아웃소싱 회사의 직원 60명을 가르쳤던 UE4 개발 강좌에서 작은 예시 프로젝트를 준비할 때 이 시스템을 사용해본 적이 있습니다. 그러나 당시 실험단계였던 시스템을 작은 교육용 프로젝트에서 사용해 보는 것과 야심 찬 대규모 상업용 프로젝트에 적용하는 것에는 큰 차이가 있었습니다.
팀에서 처음에 많은 우려를 표했는데, 충분히 그럴 만했습니다. 당시 GAS는 에픽에서 많은 지원을 받지 못했습니다. 알고 계시겠지만, 이 플러그인은 에픽이 파라곤 프로젝트를 종료한 이후 출시되었으며, 초기에는 이 게임의 핵심이기도 했습니다. 하지만 저는 이 사례를 프로덕션에 GAS를 사용해도 되겠다는 증거로 받아들였고, 팀에서 이 기능의 부족한 부분을 채울 수 있으리라고 믿었습니다. 다행히 제 생각이 맞았습니다.
설명에 [지원되지 않음]이 적힌 GAS 플러그인
언리얼 엔진 4.20이 출시될 즈음이었던 당시 인터넷에는 커뮤니티의 일부 애호가들이 쓴 글을 제외하면 GAS 관련 문서가 별로 없었습니다. 그래서 저희는 직접 연구를 시작했습니다. 플러그인 코드를 한 줄씩 점검하고 브레인스토밍 세션에서 모든 장점과 단점을 공유했습니다.
그 결과 GAS를 저희 게임에 통합하면 다음과 같이 장점이 압도적으로 많다고 판단했습니다.
당시 단점은 명확했습니다. 복잡한 데 비해 공식 문서와 지원이 부족했다는 것입니다. GAS는 복잡한 시스템이며 사용 접근법은 회사마다, 프로젝트마다 달라집니다. 이 시스템으로 모범 사례를 구축해나가는 데도 시간이 제법 소요됐습니다.
통합 단계에서 저희는 목표를 달성하기 위한 모든 기본 메커니즘을 점검했고, 모두 문제없이 처리했죠. 이 시점에서 GAS라면 자사의 액션 필터 시스템을 완전히 대체할 수 있겠다고 생각했습니다. 저희 시스템과 유사한 데다 어빌리티 실행 제어 메커니즘에서는 더 뛰어났기 때문입니다. 이렇게 GAS로 전환한 뒤에는 모든 플레이어 액션을 별도의 어빌리티로 바꾸기 시작했고, 그 결과 AHBaseCharacter와 AHPlayerCharacter 클래스(클래스에 접두사 AH를 붙임)가 훨씬 가벼워졌습니다.
이제 자체 어빌리티 시스템의 아키텍처를 디자인할 필요 없이 수많은 어빌리티를 만들 수 있게 됐습니다. 덕분에 시간이 정말 많이 절약됐습니다. 하지만 어빌리티를 추가할수록 게임플레이 상호연결/종속성이 더 복잡해졌습니다.
GAS로 작업하는 초반에는 여러 어려움을 겪었지만, 이런 문제는 자체 시스템을 개발하고 구현할 때의 어려움과는 비교도 되지 않았습니다.
브레인스토밍 세션
어빌리티와 이펙트 구성에 딱 맞는 공식을 찾은 뒤부터는 모든 것이 순조로웠습니다.
결국 이 새로운 접근법을 통해 저희는 AI 캐릭터의 액션을 별도의 어빌리티로 옮기기 시작했습니다. 덕분에 저희의 비헤이비어 트리가 가벼워지고 데이터 기반 AI 파이프라인을 사용한 캐릭터 구성을 더욱 신속히 진행할 수 있었습니다. 그럼, 저희의 GAS 사용 사례 일부를 살펴보겠습니다.
시스템에 익숙하지 않은 분들을 위해 설명하자면, 일반적인 GAS 파이프라인에는 다음과 같이 네 개의 주요 클래스가 있습니다. 먼저 어빌리티 시스템 컴포넌트는 오너에 어태치되고, 어트리뷰트 세트는 오너의 프로퍼티로 정의되며, 게임플레이 이펙트는 어빌리티 시스템 컴포넌트의 오너에게 적용되어 어트리뷰트 세트에서 정의된 어트리뷰트를 수정합니다. 마지막으로 어빌리티는 게임플레이 태그와 이펙트에 의해 제어되는 액션입니다. 그 외에 게임플레이 태스크(어빌리티의 서브 오브젝트)와 게임플레이 이펙트의 비주얼 피드백 제공을 지원하는 게임플레이 큐 등 선택적 클래스도 있습니다.
모든 것을 총괄하는 게임플레이 태그
우선 게임플레이 태그부터 살펴보면 좋겠습니다. GAS보다 UE4에 먼저 추가된 이 서브시스템은 계층형 태그(라벨)를 정의하고 이를 오브젝트에 적용하여 여러 대미지 유형을 구별하는 등 다양한 목적으로 사용할 수 있게 해 줍니다.
문드피쉬의 일반적인 게임플레이 태그 카테고리
저희에게는 게임플레이 태그의 계층구조를 엄격하게 조직하는 것이 대단히 중요했습니다. 각 어빌리티에는 자체 어빌리티 태그(어빌리티 서브트리)와 자체 금지 태그(금지 서브트리)가 있습니다.
모든 것을 정리해 두면 전체 프로젝트의 어빌리티 작업에서 동일한 접근법을 제어하고 유지하는 데 도움이 됩니다.
기본 캐릭터 어빌리티용 게임플레이 태그
금지 이펙트
통합 초기에 내린 의사결정 가운데 액션 필터 대체에 도움이 되었던 것은 금지 이펙트를 사용하는 것이었습니다. 이 이펙트는 어빌리티를 통해서, 또는 다른 장소로부터 직접 캐릭터에 추가될 수 있습니다. 이 이펙트의 유일한 목적은 태그를 부야하여 활성화된 어빌리티를 중단시키는 것입니다.
그 예로는, RestoreStamina 어빌리티가 있습니다. 이는 항상 활성 상태인 어빌리티로, RestoreStamina 게임플레이 이펙트를 적용합니다. 무한한 이펙트이며 주된 목적은 플레이어 캐릭터의 AttributeSet(GAS 컴포넌트 오너의 모든 어트리뷰트를 지정하는 데 필요한 특수 클래스) 내에 정의된 스태미나 어트리뷰트에 0.5초마다 상수 플로트 값을 더하여 플레이어 캐릭터의 스태미나를 회복하는 것입니다. 어떤 어빌리티가 금지 태그 'Prohibitions.RestoreStamina'를 부여하면 에셋 세팅에 정의된 대로 이펙트 GE_RestoreStamina가 중단됩니다(아래 스크린샷 참조).
저희 게임 내의 어빌리티 대부분은 해당 어빌리티를 금지하는 금지 태그가 적용될 경우 활성화되지 않습니다. 아토믹 하트처럼 플레이어가 50개 이상의 어빌리티를 가질 수 있는 게임에서는 매우 복잡해집니다.
비용 이펙트
태그 기반 어빌리티의 실행 규칙/전제 조건 디버깅 접근법에 대해 말씀드리기 전에 비용 이펙트에 대한 모범 사례를 하나 공유하고자 합니다. 이런 이펙트는 어빌리티 실행에 리소스를 사용해야 할 때 필요합니다. 물론 이런 이펙트가 어빌리티에 지정되면 적용 전에 확인을 거칩니다. 예를 들어 저희 게임에는 강력한 근접 타격 어빌리티에 즉각적으로 스태미나 비용이 소요됩니다. 플레이어 캐릭터의 스태미나가 다 떨어지면 이 어빌리티를 실행할 수 없습니다. 스태미나가 충분하다면 어빌리티가 실행되고 스태미나가 비용 이펙트에 정해진 값만큼 줄어듭니다.
자체 디버깅 툴
GAS를 활용한 개발 도중에는 여러 어빌리티, 이펙트, 태그, 게임플레이 큐를 쉽게 얻을 수 있습니다. 그래서 새 어빌리티를 추가할 때는 그 모든 것을 고려해야 합니다. 그렇지 않으면 '어빌리티에 갇히는' 상황이 발생하기 쉽습니다. 이는 현재 활성 상태인 어빌리티가 다른 여러 어빌리티를 차단해서 플레이어가 말 그대로 아무것도 하지 못하는 상황을 말합니다. 저희는 이 문제를 해결하기 위해 아주 단순하면서 정보가 담긴 디버그 메시지를 뷰포트에서 가져와 만들었습니다. 이 메시지는 플레이어 캐릭터에게 현재 적용된 태그와 이펙트를 보여줍니다. AI의 경우 AI 캐릭터 위치에서 가져왔으며 동일한 정보지만 각 AI 캐릭터의 어빌리티가 포함된 위젯을 표시합니다.
이 정보를 활용하면 어떤 태그/이펙트가 활성 상태여야 하는지, 활성 상태이면 안 되는지 쉽게 알 수 있습니다. 그래서 대부분의 경우 에디터 내 게임플레이 어빌리티 에셋에서 데이터를 수정하여 쉽게 문제 해결이 가능합니다.
처음 볼 땐 복잡해 보이지만 각 위젯은 접을 수 있으며 마우스를 위젯에 가져다 대면 하이라이트됩니다.
결론
게임플레이 어빌리티 시스템은 공식 프로젝트 샘플 및 라이브스트림으로 다시 지원되기 전까진 불확실한 시기를 거쳤습니다. 오늘날에는 갈수록 많은 개발자가 이 시스템을 프로젝트에 통합하고 커뮤니티에서 지식을 공유하고 있습니다.
저희 팀은 일상 작업에 유용한 강력하고 멋진 기능을 활용할 수 있게 되어 아주 기쁩니다. 이 블로그에서 설명한 저희의 경험이 다른 개발자에게 도움이 되고 영감을 줄 수 있기를 바랍니다.
저희의 개발 프로세스에 큰 힘이 되는 툴을 제공해 준 젯브레인스(JetBrains)에게도 감사의 말씀을 드리고 싶습니다.
저희가 현재 어떤 작업을 하고 있는지 더 알아보고 싶다면 트위터(Twitter)와 페이스북(Facebook)에서 저희를 팔로우하거나 아토믹 하트를 스팀(Steam)dml 찜 목록에 추가하세요! 저희 팀의 일원이 되고 싶다면 저희 웹 사이트의 채용 페이지를 참조해 주세요!
지금 언리얼 엔진을 다운로드하세요!
세계에서 가장 개방적이고 진보된 창작 툴을 받아보세요.
모든 기능과 무료 소스 코드 액세스가 포함된 언리얼 엔진은 제작에 바로 사용할 수 있습니다.