언어:
페이지 정보
엔진 버전:
언리얼 엔진

C++ 로 액션 RPG 게임플레이 제작

언리얼 엔진

이 문서의 목표는 Action RPG (ARPG)의 게임플레이 시스템을 제작한 방식을 설명하고 비슷한 시스템을 설계하는 법에 대한 예제를 제공하는 것입니다. 이미 UE4 C++ 프로그래밍 입문 문서를 읽고 일인칭 슈팅 C++ 튜토리얼 문서의 설명대로 기존 템플릿에서 기본 프로토타입을 만들어 본 분들을 대상으로 합니다. Ability(어빌리티) 시스템 전용 기능은 게임플레이 어빌리티 시스템NEW! 문서를 참고하세요.

코드 개요

대부분의 언리얼 엔진 4(UE4) 프로젝트는 기존 템플릿 또는 기존 샘플 프로젝트를 복제한 것에서 시작합니다. ARPG 의 경우 Top Down (내려보기) 템플릿과 비슷한 블루프린트 전용 게임으로 시작했다가 하이브리드 C++/블루프린트 프로젝트로 변환했습니다. 그 이력때문에 대부분의 기본 게임플레이 로직은 C++ 가 아닌 블루프린트로 구현했습니다. 그 결정 관련 요소 몇 가지는 블루프린트와 C++ 의 조화NEW! 문서에서 논했습니다. 프로젝트를 처음 만들고 변환한 이후, 게임플레이에 사용된 네이티브 클래스 계층구조를 만들었습니다. 또 C++ 코드와 콘텐츠의 디렉토리 체계 규칙과 명명 규칙도 정했습니다.

ARPG 에 사용된 소스 파일 개요입니다.

파일 이름

설명

ActionRPG.h

프로젝트의 모든 CPP 파일에 처음 포함된 모듈 헤더입니다. 여기서 대부분의 클래스가 요하는 공유 엔진 헤더와 함께 글로벌 정의도 포함해야 합니다.

RPGTypes.h

다른 클래스에 사용되는 게임 전용 구조체와 열거형을 정의하는 공유 헤더입니다. 일반적으로 순환 헤더 포함 문제를 피하려면 이 헤더를 하나 이상 만드는 것이 좋습니다.

RPGPlayerControllerBase.h

거의 대부분의 게임에서 필요한 PlayerController 의 게임 전용 서브클래스입니다. ARPG 의 경우 여기서 인벤토리를 대부분 처리합니다.

RPGCharacterBase.h

Character 의 게임 전용 서브클래스입니다. ARPG 에서는 모든 Blueprint Character 가 이 한 클래스를 상속하지만, 여러 캐릭터 유형으로 상속이 필요한 게임도 많습니다.

RPGGameInstanceBase.h

거의 대부분의 게임에서 필요한 GameInstance 의 게임 전용 서브클래스입니다. 전체 게임에 선언되는 Game Instance (게임 인스턴스)는 하나뿐이므로, 글로벌 게임 데이터를 저장하기 좋은 곳입니다.

RPGGameModeBase.h, RPGGameStateBase.h

Game Mode (게임 모드) 및 스테이트 서브클래스입니다. ARPG 는 대부분의 맵 전용 게임플레이 로직이 블루프린트라 스텁만 있는데, C++ 코드로 여러가지 모드와 스테이트를 만드는 게임도 많습니다.

RPGBlueprintLibrary.h

특정 액터에 묶이지 않은 게임 전용 블루프린트 함수를 노출합니다. 거의 모든 게임에서 하나 이상 필요합니다.

RPGSaveGame.h

디스크에 인벤토리/경험치 정보를 저장하는 데 사용하는 클래스로, 아래 자세히 설명합니다.

RPGAssetManager.h

인벤토리 시스템에 사용되는 AssetManager (애셋 매니저)의 서브클래스로, 아래 자세이 설명합니다.

RPGInventoryInterface.h

수동 형변환 없이 RPGCharacterBaseRPGPlayerControllerBase 에게 인벤토리 쿼리를 할 수 있도록 해주는 네이티브 인터페이스입니다.

Items/RPGItem.h 와 그 서브클래스

다양한 인벤토리 아이템 유형입니다.

Abilities/RPGAbilitySystemComponent 외 기타

어빌리티 시스템에 사용됩니다. 액션 RPG 의 게임플레이 어빌리티NEW! 문서를 참고하세요.

ActionRPGLoadingScreen Module

게임을 처음 로드할 때나 맵을 이동할 때 텍스처를 표시하는 데 사용되는 간단한 C++ 로딩 화면입니다. 주요 ARPG 게임 모듈보다 먼저 로드해야 하므로 별도의 모듈입니다.

ARPG 에는 없지만 여러가지 다른 언리얼 엔진 4(UE4) 게임은 Editor Module (에디터 모듈)이 있어 UE4 에디터에 사용되는 부가 UI 또는 툴을 추가합니다.

네이티브 클래스를 생성했으면 프로젝트 세팅 을 변경하여 올바른 Game Mode , Game Instance , Asset ManagerNEW! 클래스를 스폰해야 합니다. 새 변경사항을 프로젝트에 반영하도록 맵 세팅도 변경해야 할 수 있습니다.

인벤토리 및 애셋 매니저

ARPG 는 애셋 매니저NEW! 시스템을 사용하여 인벤토리 아이템을 로드 및 액세스합니다. 애셋 매니저는 원래 여러가지 다른 상황 및 전체 게임에서 사용할 수 있는 애셋을 관리하도록 설계되어, 일반적으로 모든 인벤토리 아이템에 적용됩니다. ARPG 의 경우 인벤토리 아이템 유형은 네 가지입니다.

  • Weapons: 무기는 플레이어가 장착하여 근접 피해를 입힐 수 있는 무기를 나타내는 블루프린트입니다.

  • Skills: 스킬은 파이어볼같은 특수 공격으로 플레이어가 장착하여 사용하면 즉시 범위 피해를 입힐 수 있습니다.

  • Potions: 포션은 사용하면 치유 또는 마나를 채워주는 일회용 소모성 아이템입니다.

  • Tokens: 토큰은 획득한 소울 및 경험치같은 것을 기록하는 단순한 카운터입니다.

이 아이템 각각은 URPGItem 을 상속하는 고유 C++ 클래스가 있고 DefaultGame.iniAssetManagerSettings 섹션에서 정의합니다. ARPG 에 아이템 블루프린트는 만들지 않기로 결정했는데, 별도의 로직이나 구조체 상속도 없고 각 게임마다 다를 것이기 때문입니다. 아이템 베이스 클래스 각각은 사용할 아이콘같은 UI 정보는 물론 특정 아이템을 장착했을 때 어떤 능력을 부여할지와 같은 게임플레이 정보를 제공합니다.

플레이어가 소유한 아이템은 URPGPlayerControllerBase 인스턴스의 다음 두 맵 프로퍼티에 저장합니다.

  • 첫 맵은 URPGItem* 에서 FRPGItemData 로, 수와 레벨을 저장합니다.

  • 두 번째 맵은 FRPGItemSlot 에서 URPGItem* 로, "무기 슬롯 1"에 저장된 특정 아이템을 설명합니다.

유효 아이템 슬롯 목록과 기본 인벤토리는 BP_GameInstance 에 저장됩니다. Player Controller 네이티브 클래스는 인벤토리 아이템 추가, 제거, 쿼리는 물론 어빌리티 시스템과의 상호작용을 위한 API 를 제공합니다. ARGP 의 각 아이템 유형은 프라이머리 애셋 유형이므로, FPrimaryAssetType 구조체의 용도를 우리 "아이템 유형"으로 변경한 뒤 필터 함수로 전달합니다. ARPG 는 인게임 스토어를 제공하므로 시작 시 게임의 모든 아이템을 미리 로드해야 합니다. 그 작업에 BP_GameInstance 의 로직을 사용합니다.

클릭하면 이미지 원본을 확인합니다.

AsyncLoadPrimaryAssetList 노드는 결국 URPGAssetManagerLoadPrimaryAssets 함수를 호출하여 지정된 유형의 모든 아이템 비동기 로드를 시작합니다. 로드가 끝나면 게임 인스턴스에 저장된 맵에 추가한 뒤 스토어 UI 에서 사용합니다. 한 가지 중요한 점은 LoadPrimaryAssets 을 호출하면 그 애셋 레퍼런스가 전혀 없어도 Unload 를 호출할 때까지 메모리에 유지합니다. RPGAssetManager 서브클래스는 비교적 단순한데, 각 아이템 유형에 대한 정적 유형 조금, 그리고 디스크에서 인벤토리를 로드할 때 사용하는 ForceLoadItem 함수만 선언합니다.

ARPG 의 경우 인벤토리 아이템을 사용하는 로직은 거의 BP_Character 블루프린트에 있는데 플레이어와 적 블루프린트 모두 공유하지만, 네이티브 C++ 에 아이템 구현을 하는 게임도 많습니다. 또 인벤토리는 어빌리티 시스템과의 상호작용이 많습니다. 자세한 내용은 게임플레이 어빌리티 시스템NEW! 문서를 참고하세요.

세이브 게임

ARPG 는 플레이어의 인벤토리를 (소울/경험치 포함해서) 디스크에 저장할 때 네이티브 구조체, URPGSaveGame 클래스를 사용합니다. 일반적으로 중요한 정보는 네이티브 구조체를 사용해서 저장해야 하는데, 그래야 네이티브 버전 관리 및 픽스업 코드를 사용할 수 있기 때문입니다.URPGSaveGame 의 경우 ERPGSaveGameVersion 열거형과 Serialize 함수의 픽스업 코드를 사용하여 구현했습니다. 그 이유는 사용자 정의 구조체는 언제든 실수로든 수정 가능하기 때문입니다. 개발자가 필드를 삭제 또는 이름변경하려는 경우, 플레이어의 세이브 게임에 데이터 손실이 발생하여 플레이어가 저장한 데이터가 완전 깨질 수 있습니다. 일반적으로 중요 데이터는 버전 관리가 있는 네이티브 구조체를 사용하여 구현해야 합니다.

ARPG 세이브 게임은 PrimaryAssetIds 를 사용하여 인벤토리를 ItemType: ItemName 형태의 스트링으로 저장합니다. 아이템 레퍼런스 저장에 /Game/Items/ItemName.ItemName 와 같은 애셋 경로보다 안전항 방법인데, 애셋을 옮겨도 레퍼런스가 깨지지 않기 때문입니다.애셋 이름을 변경하면, PrimaryAssetIdRedirects 또는 네이티브 코드를 사용하여 고칠 수 있습니다. ForceLoadItem 를 사용하면 아이템이 이미 메모리에 있지 않은 경우 동기 로드하여 PrimaryAssetId 에서 URPGItem 으로 변환합니다 (ARPG 의 경우 위에 언급한 스토어 미리 로드때문에 거의 그렇습니다).

URPGGameInstanceBase 는 인벤토리 실제 저장과 로드를 처리하며, BP_GameInstance 에 설정한 변수를 사용합니다. Save 함수가 네이티브 코드에서 액세스 가능하도록 하는 것이 중요한데, 인벤토리에서 아이템을 추가 또는 제거할 때마다 Player Controller 가 인벤토리를 강제 저장하기 때문입니다. 필요한 경우 블루프린트에서 수동 호출할 수도 있습니다. ARPG 의 경우 저장은 SaveGameToSlot 블루프린트 함수를 사용하여 디스크에 쓰지만, 네이티브로 구현하면 나중 시점에 서버측 솔루션으로 변경할 수 있습니다. Options (옵션) 메뉴는 네이티브 세이브 게임 구현을 사용하지 않는데, 데이터가 손실되어도 큰 상관이 없기 때문입니다. 또 그 정보는 항상 로컬 디바이스에 저장하는 것이 좋을 것입니다.

모든 게임은 게임 개발 초기에 세이브 게임 관리 계획을 세심하게 고려해야 합니다.

릴리즈용 패키지

게임플레이 인프라를 구축하고 팀이 마케팅 콘텐츠 제작을 시작하면, 마지막 남은 중요 프로그래밍 작업은 게임을 패키지와 릴리즈 준비하는 것입니다. 기본 UE4 패키지는 릴리즈 빌드에 필요한 것보다 많은 콘텐츠가 추가되는데, 모바일같은 플랫폼에서는 문제가 될 수 있습니다. ARPG 의 경우 첫 단계는 ARPG 에 꼭 필요한 콘텐츠만 포함되었나 확인하는 것이라 이 작업을 돕기 위해 애셋 매니저NEW! 를 사용했습니다.

Primary Asset Type 구성 파일의 “CookRule=AlwaysCook” 섹션은 프로젝트의 Content 폴더에 있는 모든 아이템을 최종 게임에 쿠킹하도록 합니다. Main MenuGameplay 맵이 ARPG 에 포함되었는지 확인하기 위해 Package Settings+MapsToCook 줄에 둘 다 추가했습니다. ARPG 에 필요한 콘텐츠가 모두 추가되었는지 확인한 다음 UE4 에디터에서 모바일 플랫폼용으로 프로젝트 패키지를 만들어 정상 작동하는지 확인했습니다. 패키지 게임이 정상 작동하는지 프로젝트의 콘텐츠가 전부 포함되었는지 확인한 후 다운르도 및 메모리 크기를 줄이는 방법을 살펴봤습니다. ARPG 는 모바일 플랫폼을 대상으로 하므로 다운로드 및 메모리 크기는 최대한 줄이려 했습니다. 설치 크기와 메모리 사용 공간을 줄이기 위한 방법은 다음과 같습니다.

  1. 사용하지 않는 플러그인 을 비활성화합니다. 이 작업을 했더니 ARPG 전체 프로젝트 크기가 30 MB 줄었습니다.
    ARPG_DisableUnusedPlugins_01.png

위 이미지에는 Augmented Reality 플러그인 비활성화만 보이지만, 모든 플러그인에 해 줘야 최대로 절약할 수 있습니다.

  1. Packaging (패키징) 세팅에서 찾을 수 있는 Exclude editor content when cooking (쿠킹할 때 에디터 콘텐츠 제외) 플래그를 활성화합니다. 이렇게 하면 /Engine/EditorMaterials 처럼 UE4 에디터 폴더에 있는 콘텐츠를 출시 프로젝트에 포함되지 않습니다.
    ARPG_SkipCookingEditorContent_01-1.png

참고로 이렇게 하면 그 머티리얼을 사용하는 게임 콘텐츠가 깨집니다. 하지만 보통은 프로젝트에서 UE4 에디터 폴더의 애셋을 사용하지 말아야 합니다.

  1. 기본적으로 UE4 는 /Game/UI 폴더와 DefaultEditor.ini 파일의 +ContentDirectories 줄에 추가된 폴더의 모든 콘텐츠를 쿠킹합니다. ARPG 는 이 폴더에 프로토타입 유저 인터페이스 아이템이 조금 있었는데 ARPG DefaultEditor.ini 파일에 인클루드를 추가하여 비활성화했습니다. 이 단계와 위 단계를 합치니 ARPG 설치 크기가 50 MB 줄었습니다. ARPG_DefaultEditorINI_01.png

  2. Asset Audit (애셋 감수) 창에서 사용할 수 있는 Size Map (사이즈 맵) 툴을 사용하여 (자세한 내용은 쿠킹과 청킹NEW! 문서 참고) 매우 비싼 텍스처와 스태틱 메시 세트를 알아낼 수 있었습니다. 이 정보를 콘텐츠 팀에 전달하여 정리하도록 했습니다. 애셋 최적화 결과 설치 크기가 다시 100 MB 줄었습니다. ARPG_SizeMapTool_01.png

  3. Project Settings > Packaging (프로젝트 세팅 > 패키징) 아래 For Distribution (배포용) 옵션을 임시 활성화하고 Build Configuration (빌드 구성)을 Development 에서 Shipping 으로 바꿨더니 ARPG 최종 크기를 더욱 잘 파악할 수 있었습니다. 일반적으로 최종 릴리즈 빌드를 쿠킹할 때 (보통 UAT 스크립트에 명령줄 옵션을 붙여) 하는 작업입니다만 프로젝트 개발 중에는 활성화하면 안됩니다. Development 빌드에서 Shipping 빌드로 바꾸니 추가로 50 MB 줄었습니다.
    ARPG_ForDistributionSettings_01.png

위 단계를 모두 거치고나니 ARPG 설치 크기가 약 230 MB 줄어 ARPG 를 여러 앱 스토에 출시하는 데 도움이 되었습니다.