Unreal5/Unreal C++
[U C++] 언리얼 빌드 시스템
taene_
2024. 7. 12. 20:53
< 언리얼 엔진의 프로젝트 구성 및 에디터 동작 방식 >
언리얼 에디터 구성
- 게임 제작을 위해 에픽 게임즈가 제공하는 저작 도구
- 언리얼 엔진의 구성
- 에디터: 게임 제작을 위해 제공되는 응용 프로그램
- 게임 빌드: EXE 파일과 리소스로 이루어진 독립적으로 동작하는 게임 클라이언트
- 언리얼 에디터에서 게임 구성 => 게임 빌드를 수행해서 사용자들한테 배포될 프로그램을 패키징
- 언리얼 에디터의 특징
- 게임 개발 작업을 위해 다양한 폴더와 파일 이름 규칙이 미리 설정되어 있다.
- 정해진 규칙을 잘 파악하고 프로젝트 폴더와 파일을 설정해야 한다.
- 에디터에서 기획과 개발을 완료한 후, 게임 빌드를 통해 최종 게임 빌드를 제작하도록 설정한다.
언리얼 에디터의 동작
- 하나의 프로젝트 = 게임 어플리케이션
- 프로젝트 폴더의 uproject 확장자를 더블 클릭하면 에디터가 트리거 된다.
- 에디터 실행 방식
- uproject 확장자는 윈도우 레지스트리에 등록되어 있다.
- 등록이 안되어 있다면 런처를 실행해 등록한다.
- UnrealVersionSelector 프로그램으로 프로젝트 정보가 넘겨진다.
- UnrealVersionSelector는 런처가 저장한 에디터 정보로부터 버전에 맞는 에디터를 실행한다.
- uproject 확장자는 윈도우 레지스트리에 등록되어 있다.
에디터 버전 정보의 파악
- 프로젝트.uproject 텍스트 파일에 정해져있다.
- .uproject 확장자는 에디터를 띄우기 위한 명세서 역할을 한다.
- 버전 내용은 JSON 형식으로 구성되어 있다.
- 파일에 기록된 버전 정보를 바탕으로 에픽 런처가 지정한 정보를 찾아 에디터를 실행한다.
- ProgramData/Epic/UnrealLauncher 폴더에 관련 정보가 있다.
- JSON 형식으로 설치된 언리얼 버전 정보가 기록되어 있다.
빈 폴더에서 에디터 열어보기
- 방법
- 빈 폴더 생성(UnrealBuildSystem)
- 텍스트 파일 생성(UnrealBuildSystem.txt) 및 내용 작성
- 해당 txt파일을 .uproject 확장자로 변경 -> uproject 실행 후 5개의 파일들 생성됨
- Config: 프로젝트 설정에 필요한 정보를 보관하는데 사용
- Content: 애셋들을 보관하는데 사용
- DerivedDataCache: 사용하는 애셋들의 주요 정보를 미리 캐싱해두는 역할
( 있으면 로딩이 빠르게 되지만, 용량 확보를 위해 삭제 가능 ) - Intermediate: 임시적으로 사용되는 중간 결과물들을 보관하는데 사용
( 용량이 크다 싶으면 언제든지 계속 삭제 가능 ) - Saved: 임시로 무언가를 저장하는데 사용
( 의도적으로 어떤 데이터를 저장하지 않았다면 삭제 가능 )
< 언리얼 엔진의 모듈 시스템 >
언리얼 프로젝트의 종류
- 블루프린트 프로젝트
- C++ 코드가 없는 언리얼 프로젝트
- 언리얼 엔진이 제공하는 기본 기능을 활용해 게임을 제작하는 프로젝트
- 언리얼 엔진은 게임 제작에 필요한 기능을 모듈이라는 단위로 제공하고 있다.
- 언리얼 엔진의 모듈을 상속받아 블루프린트를 활용해 모든 기능과 로직을 구현하는 방식
- 언리얼 C++ 프로젝트
- 언리얼 엔진 C++ 모듈에 개발자가 추가로 자신만의 C++ 모듈을 추가할 수 있다.
- 언리얼 엔진 모듈과 개발자 모듈을 함께 사용하는 프로젝트
- 언리얼 엔진 C++ 모듈
- 언리얼 엔진의 소스코드는 모두 모듈(Module) 단위로 구성되어 있다.
- 모듈을 컴파일함으로써 에디터 및 게임에 우리가 제작한 로직을 공급할 수 있다.
- 모듈 단위로 구성된 C++ 소스 코드를 컴파일한 결과물은
- 에디터 용으로는 DLL 동적 라이브러리를 제공하고
- 게임 용으로는 정적 라이브러리로 컴파일 되어서 실행파일 안에 들어가게 된다.
- 에디터 용 모듈은 언제나 UnrealEditor-{모듈이름}.DLL 이름 규칙을 가지고 있다.
- /Epic Games/UE_5.1/Engine/Binaries/Win64 에서 확인 가능
언리얼 C++ 모듈 추가
- 기본 언리얼 모듈에 우리가 제작한 C++ 모듈을 추가해 에디터를 띄우고 싶은 경우
- 우리가 만든 에디터 모듈(DLL 동적 라이브러리)을 빌드 폴더에 넣어줘야 한다.
- Windows의 경우: Binaries/Win64 폴더에 해당 DLL을 넣어야 한다.
- 빌드된 모듈 목록이 있는 UnrealEditor.modules 파일도 같은 폴더에 넣어줘야 인식된다.
- uproject 명세서에 모듈 이름을 지정하고 에디터를 실행한다.
- 방법
- 추가하고 싶은 모듈(실습에선 저번에 만들었던 프로젝트의 Binaries 폴더)을 추가한다.
- .uproject 파일에 "Modules" 내용을 추가 기입한다.
모듈 C++ 코드의 관리
- 언리얼 프로젝트가 소스 코드를 관리하는 규칙에 따라 소스 코드 구조를 구성해야 한다.
- 소스 코드는 멀티 플랫폼 빌드 시스템을 지원하기 위해 특정 프로그램에 종속되어 있지 않고 언리얼만의 규칙을 가진다.
- 실제 빌드를 진행하는 주체: Unreal Build Tool이라는 C# 프로그램
- Source 폴더에 지정된 규칙대로 소스를 넣으면 플랫폼(windows, mac, linux)에 맞춰서 알아서 컴파일을 진행한다.
Source 폴더의 구조
- Source 폴더
- 타겟 설정 파일: 전체 솔류션이 다룰 빌드 대상을 지정하는 파일
- {프로젝트이름}.Target.cs: 게임 빌드 설정
- {프로젝트이름}Editor.Target.cs: 에디터 빌드 설정
- 프로그램, 서버와 같은 다른 설정 파일들도 존재한다.
- 모듈 폴더 ( 보통은 프로젝트 이름으로 모듈 이름을 지정 )
- 모듈 설정 파일: 하나의 모듈을 빌드하기 위해 추가해야할 정보를 설정하는 곳( C++ 프로젝트 설정 정보 ),
모듈을 빌드하기 위해 참조할 다른 모듈에 대한 정보를 지정하는 곳
- {모듈파일}.Build.cs: 모듈을 빌드하기 위한 환경 설정
- 소스 코드 파일 ( .h 및 .cpp 파일들 )
- 모듈 설정 파일: 하나의 모듈을 빌드하기 위해 추가해야할 정보를 설정하는 곳( C++ 프로젝트 설정 정보 ),
- 타겟 설정 파일: 전체 솔류션이 다룰 빌드 대상을 지정하는 파일
게임 프로젝트의 소스
- 내가 만든 소스가 게임 프로젝트의 C++ 모듈이 되기 위해 필요한 것
- 모듈을 구현한 선언할 헤더와 소스 파일이 필요하다.
- 주로 {모듈이름}.h와 {모듈이름}.cpp로 지정한다.
- 모듈의 뼈대 제작
- 매크로를 통해 기본 뼈대 구조를 제작
- IMPLEMENT_MODULE: 일반 모듈(유용한 기능을 제공해주는 C++ 코드 라이브러리 등)
- IMPLEMENT_GAME_MODULE: 게임 모듈(게임 제작에 관련있는 모듈)
- IMPLEMENT_PRIMARY_GAME_MODULE: 주 게임 모듈(게임 제작에 가장 중심이 되는 전체적인 게임을 동작하는데 사용하는 로직들을 모아둔 모듈)
- 매크로를 통해 기본 뼈대 구조를 제작
- 일반적으로 게임 프로젝트는 주 게임 모듈을 하나 선언해야 한다.
- 기본 세팅이 끝난 후, uproject 파일을 우클릭해서 Generate Visual Studio project files 메뉴를 선택하면 UnrealVersionSelector 프로그램이 알아서 UnrealBuildTool을 가동해서 Intermediate 폴더에 프로젝트 관련 파일을 자동으로 생성해준다.
수동으로 모듈 추가해보기
// UnrealBuildSystem.Build.cs
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class UnrealBuildSystem : ModuleRules
{
public UnrealBuildSystem(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore"});
PrivateDependencyModuleNames.AddRange(new string[] { });
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
}
}
// UnrealBuildSystemEditor.Target.cs
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.Collections.Generic;
public class UnrealBuildSystemEditorTarget : TargetRules
{
public UnrealBuildSystemEditorTarget( TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
DefaultBuildSettings = BuildSettingsVersion.V2;
IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1;
ExtraModuleNames.Add("UnrealBuildSystem");
}
}
// UnrealBuildSystem.h
#pragma once
#include "CoreMinimal.h"
// UnrealBuildSystem.cpp
#include "UnrealBuildSystem.h"
#include "Modules/ModuleManager.h"
// IMPLEMENT_PRIMARY_GAME_MODULE(모듈을 구현한 클래스 지정(언리얼 엔진이 제공하는 게임 모듈 기본 클래스), 모듈 이름, 게임 이름)
IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, UnrealBuildSystem, "UnrealBuildSystem");
모듈간의 종속 관계
- 모듈 사이에 종속 관계를 설정해 다양한 기능을 구현할 수 있다.
- 우리가 만드는 게임 모듈도 언리얼 엔진이 만든 모듈을 활용해야 한다.
- 언리얼 엔진이 제공하는 모듈 사이에도 종속 관계가 있다.
- 하나의 모듈에 너무 많은 코드가 들어가면 언리얼 엔진은 빌드 방식을 변경하기 때문에 프로젝트가 커질 수록 모듈을 나누어서 관리하는 것이 유리하다. ( SubModule 추가 )
모듈의 공개와 참조
- 모듈 내 소스를 필요한 만큼만 공개해야 모듈 간 의존성을 줄이고 컴파일 타임을 최소화할 수 있다.
- 공개할 파일은 모두 Public 폴더로
- 외부로 공개할 클래스나 함수 선언에는 모듈이름_API 매크로를 붙일 것 ( {모듈이름}_DLL )
- 예외) 예전 언리얼 엔진은 Classes 폴더가 있어서 Public 폴더 역할을 하며 언리얼 오브젝트를 관리했다.
- 숨길 파일은 모두 Private 폴더로
- 이 곳의 .h 파일들의 선언의 모듈이름_API 매크로를 삭제해서 안전하게 외부 모듈이 참조할 수 없도록 지정하는 것이 좋다.
- 게임 모듈에서는 Build.cs 설정을 통해 참조할 모듈을 지정할 수 있다.
< 플러그인 시스템 >
플러그인 시스템
- 게임 프로젝트 소스에 모듈을 추가하는 방법은 분업이 어렵다는 단점이 있다.
- 따라서 공용 기능들을 모아두는 모듈들은 프로젝트로부터 아예 분리시켜서 스스로도 동작할 수 있도록 설계하는 것을 고려해 볼 수 있다.
- 모듈만 독립적으로 동작하는 플러그인 구조를 만들어 분업화하는 것이 바람직하다.
- [모듈간의 종속 관계] 그림에서 SubModule을 플러그인으로 분리하는 것을 고려함!
플러그인 구조
- 플러그인은 다수의 모듈과 게임 콘텐츠를 포함하는 포장 단위
- 에디터 설정을 통해 유연하게 플러그인을 추가하거나 삭제할 수 있다.
- 플러그인 구조
- 플러그인 명세서 ( uplugin 파일 )
- 플러그인 리소스 ( Resource 폴더, 에디터 메뉴용 아이콘 )
- 콘텐츠
- 모듈 폴더
- 이러한 플러그인은 마켓 플레이스 판매로도 이어질 수 있도록 여러 설정을 추가할 수 있다.
- 에디터 - Edit - Plugins 에서 만든 Plugins들을 자유롭게 추가 및 삭제를 할 수 있다.
< 게임 빌드 시스템 >
게임 빌드
- 게임 타겟 설정을 추가하면 게임 빌드 옵션이 추가된다. ( Source/UnrealBuildSystem.Target.cs )
- 게임 타겟으로 빌드된 모듈은 정적 라이브러리로 실행 파일에 포함된다.
- 게임이 실행되기 위해서는 실행 파일과 콘텐츠 애셋이 함께 있어야 한다.
- 빌드: 실행 파일을 생성하기 위한 컴파일
- 쿠킹: 지정한 플랫폼에 맞춰 콘텐츠 애셋을 변환하는 작업
- 패키징: 이들을 모두 모아서 하나의 프로그램으로 만드는 작업
- 게임 빌드 옵션
- Development Editor: 빌드 솔루션(Ctrl+Shift+B)를 수행하고 에디터(Ctrl+F5)를 열 수 있는 모드
- DebugGame Editor: 코드에 breakpoint(F9)를 걸고 에디터를 열어 게임을 실행 후 디버깅을 할 수 있는 모드
- Shipping: 사용자한테 배포할 최종 게임의 코드를 만들어 내는 작업
- 이때, 모든 코드들이 최적화돼서 들어가게 되는데, 코드들 중 check()나 ensure() 같은 어설션 매크로들은 쉬핑 빌드에서 제외된다.
- Shipping으로 빌드하면 결과물이 exe 파일로 나온다. ( Binaries/Win64/-.exe )
게임 패키징 과정