언리얼 엔진(UE) 모듈 은 코드를 정리하고, 프로젝트의 빌드 시간을 단축하고, 시스템 및 코드의 로드/언로드 프로세스를 설정할 수 있는 유용한 수단입니다. 이 가이드에서는 C++에서 신규 런타임 모듈을 구현하는 데 필요한 단계를 처음부터 설명합니다. 이 모듈은 프로젝트의 프라이머리 모듈 과 다릅니다.
예제에서 사용할 모듈의 이름은 ModuleTest 입니다.
1. 필수 설정
이 가이드를 따르려면, 우선 MyProject 라는 이름의 신규 프로젝트를 생성하고 C++ 프로젝트 로 지정합니다. 블루프린트만 사용한 프로젝트로 진행할 경우, 언리얼 에디터에서 C++ 코드를 새로 만들고 C++ 프로젝트로 변환하세요.
2. 디렉터리 구성하기
우선 모듈과 모듈의 코드를 포함하는 디렉터리를 구성해야 합니다.
프로젝트의 루트 디렉터리로 이동한 뒤 Source 폴더를 엽니다.
프로젝트의 Source 폴더에서 ModuleTest 라는 폴더를 생성합니다. 이 폴더는 모듈의 루트 디렉터리 역할을 합니다.
모듈의 루트 디렉터리 안에 Private 과 Public 이라는 두 개의 폴더를 생성합니다.
디렉터리의 구조는 다음과 비슷해야 합니다.
MyProject
Source
MyProject.Target.cs
MyProjectEditor.Target.cs
MyProject(프라이머리 게임 모듈 폴더)
Private
Public
MyProject.Build.cs
게임 모듈에 포함된 기타 C++ 클래스
ModuleTest
Private
Public
3. Build.cs 파일 생성하기
언리얼 빌드 툴(Unreal Build Tool, UBT) 에서 종속성을 확인하기 위해 프로젝트의 디렉터리를 살펴볼 경우, 툴은 IDE 솔루션 파일을 무시하고 Source 폴더에 있는 Build.cs
파일을 대신 확인합니다. 모듈마다 Build.cs
파일이 있어야 하며, 없으면 UBT에서 발견하지 못합니다.
Build.cs
파일을 구성하려면 다음 단계를 따르세요.
모듈의 루트 디렉터리에
ModuleTest.Build.cs
라는 파일을 생성합니다. 해당 파일을 열고 다음 코드를 추가합니다.using UnrealBuildTool; public class ModuleTest: ModuleRules { public ModuleTest(ReadOnlyTargetRules Target) : base(Target) { } }
실행하면 모듈이 언리얼 빌드 시스템에 표시됩니다.
생성자가 다음처럼 보이도록 편집합니다.
public ModuleTest(ReadOnlyTargetRules Target) : base(Target) { PrivateDependencyModuleNames.AddRange(new string[] {"Core", "CoreUObject", "Engine"}); }
실행하면
Core
,CoreUObject
,Engine
모듈을 귀하의 모듈에 프라이빗 종속성의 형태로 추가합니다. 이에 따라 가이드 후반에 등장하는 몇 가지 클래스를 이 모듈에 사용할 수 있게 됩니다.
코드를 이 모듈의 폴더에 추가할 경우, UBT에서 프로젝트를 빌드할 때와 자신이 IDE 프로젝트 파일을 생성할 때마다 해당 코드를 발견할 수 있습니다.
4. C++에서 모듈 구현하기
Build.cs
파일이 있으면 UBT에서 모듈을 발견할 수 있지만, 엔진에서 로드 및 언로드할 수 있도록 하려면 모듈을 C++ 클래스의 형태로도 구현해야 합니다.
다행히 언리얼 엔진에는 대부분의 일반 구현에 사용되는 이 프로세스를 효율적으로 만드는 매크로가 있습니다. 파일을 빠르게 구현하려면 다음 단계를 따르세요.
모듈의 루트 디렉터리로 이동한 뒤
Private
폴더를 엽니다. 이 폴더에ModuleTestModule.cpp
라는 파일을 생성합니다. 이 클래스에.h
파일을 생성할 필요는 없습니다.[모듈 이름]Module은 언리얼 엔진 소스 코드에 속한 모듈 구현 파일의 일반적인 명명 규칙입니다. 거대한 코드에서 파일을 추적할 때 유용합니다.
ModuleTestModule.cpp
안에 다음 코드를 추가합니다.#include "Modules/ModuleManager.h" IMPLEMENT_MODULE(FDefaultModuleImpl, ModuleTest);
실행하면 모듈의 디폴트 구현을 제공하여 C++ 코드에 사용할 수 있게 됩니다.
모듈의 클래스, 생성자, 시작 및 종료 함수를 직접 작성하여 훨씬 디테일한 구현을 생성할 수 있습니다. 하지만 대부분 게임플레이 모듈은 기본 구현만으로도 모듈을 로드 및 언로드할 수 있습니다.
5. 모듈 컴파일하기
모듈의 정의 및 구현이 끝나면 아주 간단한 컴파일 프로세스를 수행합니다.
MyProject.uproject
를 우클릭한 뒤 Visual Studio 파일 생성(Generate Visual Studio Files) 을 클릭하여 IDE 솔루션을 생성합니다.
새 모듈이 IDE 및 언리얼 에디터에 표시됩니다.
모듈의 코드를 다시 정리하거나, 모듈 내 Build.cs
파일의 내용을 변경할 때마다 최신 상태를 유지하기 위해 IDE 솔루션을 재생성해야 합니다.
Visual Studio에서 프로젝트를 컴파일합니다. 도중에 새로 만든 모듈이 함께 컴파일됩니다.
직접 새 모듈 추가, 모듈 디렉터리 구조 변경, C++ 파일을 이동 또는 이름 바꾸기, 모듈의 종속성 변경 같은 작업을 수행할 때마다 프로젝트 파일을 재생성하여 Visual Studio 솔루션을 업데이트한 뒤 프로젝트를 다시 컴파일해야 합니다.
언리얼 에디터가 실행 중일 때도 프로젝트를 컴파일할 수 있지만, 큰 변경사항이나 새 클래스를 반영하려면 언리얼 에디터를 닫고 재시작해야 하는 경우도 있습니다.
6. 모듈을 프로젝트에 포함하기
모듈을 컴파일할 수는 있지만, 모듈의 코드를 프로젝트에서 사용하려면 .uproject file
로 등록한 뒤 게임의 프라이머리 모듈에 대한 종속성을 만들어야 합니다.
MyProject
루트 디렉터리를 열고 텍스트 에디터에서MyProject.uproject
를 실행한 뒤, ‘Modules' 목록을 다음과 같이 편집합니다."Modules": [ { "Name": "MyProject", "Type": "Runtime", "LoadingPhase": "Default" }, { "Name": "ModuleTest", "Type": "Runtime" } ]
이 목록의 항목을 사용하면 로드할 로딩 페이즈(Loading Phase) 와 그 타입(Type) 을 설정할 수 있습니다. 이 예시는 런타임 모듈이므로, 프로젝트가 독립형 애플리케이션이나 에디터로 실행될 때도 사용할 수 있습니다.
반면 에디터 모듈은 에디터에서만 실행할 수 있습니다. 에디터 모듈은 게임 모듈이 로드된 뒤 실행되는 디폴트(Default) 로딩 페이즈도 사용합니다. 모듈의 사양에 따라 다르지만,의존성을 가진 다른 모듈이 아직 로드되지 않은 코드를 찾느라 오류를 내보낼 수도 있습니다. 이를 방지하기 위해 초기 로딩 페이즈를 사용해야 할 수도 있습니다.
MyProject/Source
폴더로 이동한 뒤MyProject.Build.cs
파일을 엽니다.ModuleTest
를PublicDependencyModuleNames
목록에 추가합니다. 다음과 같아야 합니다.PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ModuleTest" });
이제 모듈의 코드를 프라이머리 게임 모듈에 포함할 수 있습니다.
7. 모듈에 코드 추가하기
C++ 파일을 모듈의 Public
및 Private
디렉터리에 수동으로 추가하거나 언리얼 에디터에 추가할 수 있습니다.
다음 단계는 신규 클래스 마법사(New Class Wizard)로 코드를 모듈에 추가하는 방법을 안내합니다.
언리얼 에디터에서 프로젝트를 엽니다.
콘텐츠 브라우저에서 추가(Add), 새 C++ 클래스 생성(New C++ Class) 을 클릭합니다.
액터(Actor) 를 부모 클래스로 선택하고 다음(Next) 을 클릭합니다.
이름(Name) 필드 옆의 드롭다운을 찾습니다. 디폴트 이름은 MyProject(Runtime) 으로 설정되어 있을 것입니다. 드롭다운을 클릭한 뒤 ModuleTest(Runtime) 로 변경합니다.
옵션에 MyModule(Runtime)이 보이지 않을 경우, 이전 섹션을 다시 읽어보며 단계를 제대로 따랐는지 확인하세요.
클래스 이름을 ModuleActorBase 로 지정하고, 클래스 타입(Class Type) 을 퍼블릭(Public) 으로 설정한 뒤 클래스 생성(Create Class) 을 클릭합니다.
클래스의
.h
및.cpp
파일이 IDE에서 자동으로 실행됩니다. 클래스의.cpp
파일은 모듈의Private
폴더에 추가되고,.h
파일은Public
폴더에 추가됩니다.ModuleActorBase.cpp
를 열고AModuleActorBase::BeginPlay
함수에 다음 행을 추가합니다.GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Blue, TEXT("Hello, world!"));
코드를 저장하고 모듈을 컴파일합니다.
이 클래스는 게임을 시작할 때 디버그 메시지를 화면에 출력하는 간단한 액터를 정의합니다. 언리얼 에디터의 액터 배치(Place Actors) 툴로 액터를 테스트할 수 있습니다.
8. 모듈의 코드를 확장하기
마지막으로, 다음 단계를 따라 새 액터 클래스를 테스트하고 프라이머리 게임 모듈에서 해당 액터 클래스를 볼 수 있는지 테스트합니다.
언리얼 에디터에서 프로젝트를 엽니다. 새 블루프린트 클래스(New Blueprint Class) 를 생성한 뒤 모든 클래스(All Classes) 목록을 펼칩니다.
ModuleActorBase 를 부모 클래스로 선택합니다. 블루프린트 클래스의 이름을 ModuleActorBP 로 지정합니다.
콘텐츠 브라우저에서 ModuleActorBP의 사본을 게임 월드로 드래그합니다. 플레이(Play) 버튼을 클릭합니다.
ModuleActorBase가 클래스 목록에 보이지 않을 경우, 헤더가 Public
폴더에 있는지, BlueprintType UCLASS
지정자가 클래스에 포함되었는지, ModuleTest
모듈을 프로젝트의 종속성에 추가했는지 확인합니다.
최종 결과
플레이(Play)를 클릭하면 에디터는 프로젝트의 플레이를 시작하며, 디버그 메시지인 ‘Hello, world!'가 파란색 텍스트로 출력됩니다. 이 블루프린트 기반 액터는 개별 게임플레이 모듈에서 정의된 클래스를 확장합니다. 여러분은 이제 앞으로 모듈을 작성할 때 게임플레이 전용 코드의 기반이 되는 확장 가능 클래스를 생성할 수 있습니다.