모듈(Modules) 은 언리얼 엔진(UE) 소프트웨어 아키텍처의 가장 기본적인 구성 요소입니다. 모듈은 특정 에디터 툴, 런타임 기능, 라이브러리 등의 기능을 독립된 코드 단위로 캡슐화합니다.
모든 프로젝트와 플러그인에는 기본적으로 자체 프라이머리 모듈 이 있지만, 모듈을 따로 정의하여 코드를 정리할 수 있습니다.
이 페이지에서는 모듈의 구조와 언리얼 엔진 프로젝트에 사용했을 때의 이점에 대한 개요를 다룹니다.
언리얼 엔진 모듈은 C++ 20 모듈과 관련이 없습니다.
모듈 사용의 이점
프로젝트를 정리할 때 모듈을 사용하면 다음과 같은 이점이 있습니다.
-
모듈은 적절한 코드 분리를 강제하여 함수 기능을 캡슐화하고 코드의 내부를 숨깁니다.
-
모듈은 각기 다른 컴파일 유닛으로 컴파일됩니다. 따라서 변경된 모듈만 컴파일하므로 대규모 프로젝트의 빌드 시간이 대폭 단축됩니다.
-
모듈은 종속성 그래프에서 서로 연결되며, 눈에 보이는 것만 포함(Include What You Use, IWYU) 표준을 따라 헤더에 실제 사용되는 코드만 포함하도록 제한합니다. 컴파일하는 동안 프로젝트에 사용하지 않는 모듈을 안전하게 제외할 수 있다는 뜻입니다.
-
런타임 시 지정한 모듈의 로드 및 언로드 시간을 조절할 수 있습니다. 덕분에 사용할 수 있거나 활성화할 시스템을 관리하여 프로젝트의 퍼포먼스를 최적화할 수 있습니다.
-
프로젝트를 컴파일할 플랫폼 등 특정 조건에 따라 프로젝트를 포함하거나 제외할 수 있습니다.
요약하자면, 모듈로 최상의 시나리오를 도출하여 프로젝트의 모든 코드를 단일 모듈에 넣을 때보다 더 잘 정리하고, 컴파일의 효율을 개선하며, 코드의 재사용성을 높일 수 있습니다.
모듈 구성하기
다음은 모듈을 처음부터 빌드 및 구현하는 방법에 대한 개요입니다. 이 단계를 따라 하면 프로젝트에 기본적으로 포함되는 프라이머리 모듈과 기타 게임플레이 모듈을 생성할 수 있습니다.
- 프로젝트의 Source 폴더 최상위 경로에 모듈용 디렉터리를 생성합니다. 이 디렉터리의 이름은 모듈과 동일해야 합니다.
모듈은 경로 내 위치에 상관없이 Source 폴더에 있는 모든 서브디렉터리에 배치할 수 있습니다. 따라서 서브디렉터리를 사용하여 모듈을 그룹화할 수 있습니다.
-
모듈의 루트 디렉터리에
[ModuleName].Build.cs
파일을 생성하고, 이 파일로 다른 모듈과의 종속성을 정의합니다. 종속성을 정의하면 언리얼 빌드 시스템에서 모듈을 발견할 수 있습니다. -
모듈의 루트 디렉터리에 Private, Public 서브 폴더를 생성합니다.
-
모듈의 Private 서브 폴더에
[ModuleName]Module.cpp
파일을 생성합니다. 이 파일로 모듈 및 언리얼 엔진에서 모듈 관리를 위해 사용하는 일반 함수를 시작 및 중단할 수 있습니다. -
모듈을 언제 어떻게 로드할지 정하기 위해
.uproject
혹은.uplugin
파일에 속한 모듈에 환경설정 정보를 추가합니다. 모듈의 이름, 타입, 호환 가능 플랫폼, 로딩 페이즈를 포함해야 합니다. -
이 모듈을 사용해야 하는 모든 모듈의
Build.cs
파일에 종속성으로 모듈을 나열합니다. 프로젝트의 프라이머리 모듈에 대한Build.cs
파일이 포함될 수도 있습니다. -
[ModuleName].Build.cs
파일을 변경하거나 소스 파일을 다른 폴더로 옮길 때마다 해당 IDE의 솔루션 파일을 생성합니다. 이때 다음 메서드 중 하나를 사용할 수 있습니다.-
GenerateProjectFiles.bat
을 실행합니다. -
프로젝트의
.uproject
파일을 우클릭한 뒤 프로젝트 파일 생성(Generate Project Files) 을 클릭합니다. -
언리얼 에디터에서 파일(File) > 새로고침(Refresh) > Visual Studio > 프로젝트(Project) 를 클릭합니다.
-
해당 컴포넌트에 관한 자세한 정보와 설정 방법이 궁금하면 이 페이지를 계속 읽으세요. 모듈 구성에 관한 자세한 정보는 게임플레이 모듈 생성을 참조하세요.
모듈 구조 이해하기
모든 모듈은 플러그인 혹은 프로젝트의 Source 디렉터리에 배치해야 합니다. 모듈의 루트 폴더는 해당 모듈과 이름이 동일해야 합니다.
또한 루트 폴더의 모듈마다 [ModuleName].Build.cs
파일과 모듈의 C++ 코드가 Private, Public 폴더에 있어야 합니다.
다음은 권장하는 모듈 폴더 구조 예시입니다.
- [ModuleName]
- Private
- [ModuleName]Module.cpp
- 모든 .cpp 파일 및 프라이빗 헤더
- Public
- 모든 퍼블릭 헤더
- [ModuleName].Build.cs
- Private
Build.cs 파일에서 종속성 설정하기
언리얼 빌드 시스템은 IDE에 대한 솔루션 대신 프로젝트의 Target.cs
파일과 모듈의 Build.cs
파일에 따라 프로젝트를 빌드합니다.
IDE 솔루션은 코드를 편집할 때 자동으로 생성되지만, 언리얼 빌드 툴(Unreal Build Tool, UBT)은 프로젝트를 컴파일할 때 IDE 솔루션을 무시합니다.
언리얼 빌드 시스템에서 솔루션을 인식하도록 하려면 모든 모듈의 루트 디렉터리에 [ModuleName].Build.cs
파일을 배치해야 합니다.
[ModuleName].Build.cs
파일 내부에서는 모듈을 ModuleRules 클래스에서 상속받은 클래스로 정의해야 합니다. 다음은 간단한 Build.cs
파일의 예시입니다.
샘플 ModuleTest.Build.cs 파일
using UnrealBuildTool;
public class ModuleTest: ModuleRules
{
public ModuleTest(ReadOnlyTargetRules Target) : base(Target)
{
PrivateDependencyModuleNames.AddRange(new string[] {"Core"});
}
}
Build.cs
파일을 설정할 때는 주로 PrivateDependencyModuleNames,
PublicDependencyModuleNames
목록을 사용합니다. 이러한 목록에 모듈 이름을 추가하면 사용할 수 있는 모듈이 모듈 코드에 설정됩니다.
예를 들어 'Slate' 및 'SlateUI' 모듈 이름을 프라이빗 종속성 목록에 추가할 경우, 모듈에 Slate UI 클래스를 추가할 수 있게 됩니다.
프라이빗 및 퍼블릭 종속성
퍼블릭 .h
파일처럼 모듈에 있는 클래스를 퍼블릭으로 사용할 경우 PublicDependencyModuleNames
목록을 사용해야 합니다. 그러면 이 모듈에 의존하는 다른 모듈도 헤더 파일을 문제없이 추가할 수 있습니다.
.cpp
파일처럼 모듈을 프라이빗으로만 사용할 경우 모듈의 이름을 PrivateDependencyModuleNames
목록에 추가해야 합니다. 되도록 프로젝트의 컴파일 시간을 줄여주는 프라이빗 종속성을 사용하는 것이 좋습니다.
헤더 파일 내에서 전방 선언(Forward Declaration)을 사용하여 수많은 종속성을 퍼블릭이 아닌 프라이빗으로 만들 수 있습니다.
Private 및 Public 폴더 사용하기
모듈이 일반 C++ 모듈일 경우(ModuleType
이 .uproject
혹은 .uplugin
에서 External
로 설정되지 않음), 모듈의 C++ 파일을 모듈의 루트 디렉터리에 속한 Private 및 Public 서브 폴더에 배치해야 합니다.
이 파일들은 C++ 코드에 속한 Private,
Public,
Protected
액세스 지정자와 관련이 없습니다. 대신 다른 모듈의 모듈 코드에 대한 이용성을 제어합니다. 이러한 폴더를 사용할 때는 모든 .cpp
파일이 Private 폴더에 배치해야 합니다. 헤더 ( .h
) 파일은 아래 가이드라인에 따라 Private 및 Public 폴더에 배치해야 합니다.
헤더 파일을 Private 폴더에 배치한 경우, 이 콘텐츠는 보유 중인 모듈 외의 다른 모듈에 노출되지 않습니다. 이 폴더에서 클래스, 구조체, 열거형은 같은 모듈의 다른 클래스에서 액세스할 수 있지만, 다른 모듈의 클래스에서는 사용할 수 없습니다.
헤더를 Public 폴더에 배치한 경우, 언리얼 빌드 시스템이 콘텐츠를 현재 모듈에 종속된 다른 모든 모듈에 노출합니다. 외부 모듈의 클래스는 Public 폴더에 포함된 클래스를 확장할 수 있으므로, Public 폴더에 포함된 클래스, 구조체, 열거형을 사용하는 변수 및 레퍼런스를 생성할 수도 있습니다. Private,
Public,
Protected
지정자는 평소처럼 함수 및 변수에서 유효합니다.
다른 대상에 종속되지 않는 모듈을 작업할 경우 Private,
Public
폴더를 사용할 필요가 없습니다. 두 폴더 외부의 모든 코드는 Private 폴더에 있는 것처럼 행동합니다. 일반적인 예시로 게임에서 종속성 체인의 끝에 자주 위치하는 프라이머리 모듈을 들 수 있습니다.
Public
및 Private
폴더에 서브 폴더를 생성하여 코드를 추가로 정리할 수도 있습니다. Public
폴더에 새 폴더를 생성한 경우, Private
폴더에도 같은 이름의 폴더를 생성합니다. 마찬가지로 헤더 파일을 Public
폴더에 배치할 때도 Private
폴더의 동일한 폴더에 .cpp
파일을 배치해야 합니다.
언리얼 에디터의 신규 클래스 마법사(New Class Wizard)로 새 클래스를 생성하면 자동으로 두 폴더 간에 병렬 구조를 형성합니다.
C++에서 모듈 구현하기
모듈을 나머지 C++ 프로젝트에 노출하려면 IModuleInterface
를 확장하는 클래스를 생성한 뒤 IMPLEMENT_MODULE
매크로에 추가해야 합니다.
가장 간단한 구현 방법은 Private 디렉터리의 모듈에서 .cpp
파일을 생성하고 이름을 [ModuleName]Module.cpp
로 지정하는 것입니다. 여기서 [ModuleName]
은 모듈의 이름입니다. 다른 #include
선언을 전부 끝낸 후 IMPLEMENT_MODULE
매크로를 호출하여 FDefaultModuleImpl
을 클래스로 제공하세요.
ModuleTestModule.cpp
#include "Modules/ModuleManager.h"
IMPLEMENT_MODULE(FDefaultModuleImpl, ModuleTest);
FDefaultModuleImpl
은 IModuleInterface
를 확장하는 빈 클래스입니다. 이 .cpp
파일에 구현할 클래스를 직접 작성하면 더 디테일한 구현이 가능합니다.
IModuleInterface
에는 모듈이 GameInstance
클래스의 Startup,
Shutdown
함수처럼 로드/언로드를 수행할 때 트리거되는 여러 함수가 포함됩니다.
프로젝트에 모듈 사용하기
신규 언리얼 엔진 프로젝트나 플러그인을 생성할 때마다 자체 프라이머리 모듈을 프로젝트의 Source
폴더에 자동으로 구성합니다. 외부 모듈을 프로젝트 내 프라이머리 모듈의 Build.cs
파일에 추가하여 프로젝트에 포함할 수 있습니다.
예를 들어 MyProject라는 이름의 프로젝트에 게임플레이 태스크(Gameplay Tasks) 시스템을 사용하려는 경우, MyProject.Build.cs
를 실행한 뒤 'GameplayTasks' 모듈을 종속성으로 추가해야 합니다.
언리얼 빌드 툴에서는 컴파일 속도를 최적화하기 위해 프로젝트의 종속성 체인에서 발견한 모듈만 컴파일합니다. 즉, 모듈이 프로젝트에서 사용하는 어떤 Build.cs
파일에도 포함되지 않을 경우, 컴파일 중에 해당 모듈은 제외됩니다.
모듈 로드 방식 제어하기
.uproject
및 .uplugin
파일에는 프로젝트에 포함할 모듈과 로드 방식을 정의하는 Modules
목록이 존재합니다.
프로젝트 파일을 재생성할 때 모듈에 대한 항목이 존재하지 않을 경우, 이 항목을 목록에 자동으로 추가합니다. 원래는 모듈 관련 항목이 종속성 체인에 포함되어 있다고 가정하기 때문입니다. 이 목록에 포함되는 항목은 다음과 비슷합니다.
"Modules": [
{
"Name": "ModuleTest",
"Type": "Runtime",
"LoadingPhase": "Default",
},
{
"Name": "ModuleTestEditor",
"Type": "Editor",
}
]
게임플레이 모듈 대부분 이름(Name) 만 목록에 추가되며, 타입(Type) 은 Runtime
으로 설정됩니다. 모듈의 로딩 페이즈(LoadingPhase) 가 정의되지 않았다면 Default
로 설정됩니다. 이외에도 다양한 모듈 타입, 로딩 페이즈, 모듈을 로드하거나 로드하지 않을 플랫폼을 제어하는 추가 파라미터가 있습니다.
사용 가능한 모듈 타입에 관한 정보는 EHostType::Type의 API 문서를 참조하세요.
가장 흔한 모듈 타입은 Runtime
과 Editor
이며, 각각 인게임 클래스와 에디터 전용 클래스에 사용됩니다.
로딩 페이즈에 관한 자세한 정보는 ELoadingPhase::Type의 API 문서를 참조하세요.
Default
로딩 페이즈는 프로젝트에서 사용하는 게임플레이 모듈 대부분에 적합하지만, 플러그인은 미리 로딩해야 할 수 있습니다. 언리얼 에디터에서 플러그인의 C++ 클래스를 찾다가 오류가 자주 발생하면 플러그인 설정을 PreDefault
로 변경해 보세요.
이 목록에서 사용하는 기타 파라미터는 다음과 같습니다.
파라미터 | 설명 |
---|---|
IncludelistPlatforms / ExcludelistPlatforms (배열) | 목록에 포함된 플랫폼에서 컴파일할 모듈을 포함하거나 제외합니다. 플랫폼 스트링의 예시로 Win32, Win64, Mac, Linux, Android, IOS 가 있습니다. |
IncludelistTargets / ExcludelistTargets (배열) | 목록에 포함된 빌드 타깃에서 컴파일할 모듈을 포함하거나 제외합니다. 사용할 수 있는 빌드 타깃은 Game, Server, Client, Editor, Program 입니다. |
IncludelistTargetConfigurations / ExcludelistTargetConfigurations (배열) | 목록에 포함된 빌드 환경설정에서 컴파일할 모듈을 포함하거나 제외합니다. 사용할 수 있는 타깃 환경설정은 Debug, DebugGame, Development, Shipping, Test 입니다. |
IncludelistPrograms / ExcludelistPrograms (배열): | 특정 프로그램 이름 범위 내에서 컴파일할 모듈을 포함하거나 제외합니다. |
AdditionalDependencies (배열): | 모듈에서 필요로 하는 추가 종속성을 지정합니다. 대신 Build.cs 파일에서 지정해야 합니다. |