2026. 6. 23. 21:13ㆍUnreal
모듈과 플러그인
언리얼 엔진은 기능을 모듈 단위로 나눠서 관리한다.
우리가 만드는 게임 프로젝트도 사실 하나의 모듈이다. 이번엔 프로젝트 안에서 새 모듈을 직접 추가하고, 재사용 가능한 플러그인 구조까지 손으로 만들어보려고 한다.

1. 프로젝트 생성
언리얼 에디터에서 아래 순서대로 프로젝트를 생성했다.
Game -> Third Person -> C++ -> Scalable
프로젝트 이름 : HW10

2. Test 모듈 생성
source 폴더 안에 Test 폴더를 새로 만들어 모듈 파일을 여기 안에서 생성했다.
Source/
├── HW10/ ← 기존 주 모듈
└── Test/ ← 새로 만든 모듈
├── Test.Build.cs
├── Test.h
└── Test.cpp


Test.Build.cs
모듈의 의존성을 정의하는 파일이다.
이 파일이 없으면 언리얼 빌드 시스템이 이 폴더를 모듈로 인식하지 못한다.
using UnrealBuildTool;
public class Test : ModuleRules
{
public Test(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[]
{
"Core",
"CoreUObject",
"Engine"
});
}
}
Test.h / Test.cpp
// Test.h
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FTestModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
// Test.cpp
#include "Test.h"
void FTestModule::StartupModule()
{
UE_LOG(LogTemp, Warning, TEXT("=== Test Module Started! ==="));
}
void FTestModule::ShutdownModule()
{
UE_LOG(LogTemp, Warning, TEXT("=== Test Module Shutdown! ==="));
}
IMPLEMENT_MODULE(FTestModule, Test);
IMPLEMENT_MODULE 매크로가 없으면 모듈로 등록할 수 없다.
처음에 cpp파일을 만들고 실행했을 때 오류가 발생했는데, 이 부분이 없어서 그런 것이었다.
언리얼이 모듈을 로드할 때 이 매크로가 진입점 역할을 한다.
모듈 등록
파일을 만들고 빌드 시스템과 프로젝트 파일에 알려야한다.
Target.cs 수정
source 폴더에 있는

이 두 파일을 수정해준다.
// 변경 전
ExtraModuleNames.AddRange(new string[] { "HW10" });
// 변경 후
ExtraModuleNames.AddRange(new string[] { "HW10", "Test" });
.uproject 수정
HW10.uproject 파일의 내부를 수정해준다.
모듈 배열에 "Test" 모듈을 추가해준다.

LoadingPhase를 PreDefault로 설정한 이유는 주 모듈(HW10)보다 Test모듈이 먼저 로드되어야 주 모듈에서 Test모듈의 클래스를 사용할 수 있기 때문이다.
TestActor 생성
모듈의 동작을 확인하기 위해서 Test모듈 안에 Actor를 만들었다.

// TestActor.cpp
#include "TestActor.h"
ATestActor::ATestActor()
{
PrimaryActorTick.bCanEverTick = false;
}
void ATestActor::BeginPlay()
{
Super::BeginPlay();
UE_LOG(LogTemp, Warning, TEXT("=== TestActor BeginPlay! Test Module Working! ==="));
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green,
TEXT("Test Module Working!"));
}
}
이렇게 이 모듈에서 Actor의 BeginPlay가 실행되면 로그가 찍히도록 했다.
주 모듈에서 TestActor 스폰
HW10.Build.cs에 Test 의존성을 추가해준다.
PublicDependencyModuleNames.AddRange(new string[]
{
"Core", "CoreUObject", "Engine", "InputCore",
"EnhancedInput",
"Test" // 추가
});
HW10Character.cpp BeginPlay에서 스폰
#include "TestActor.h"
void AHW10Character::BeginPlay()
{
Super::BeginPlay();
FActorSpawnParameters SpawnParams;
GetWorld()->SpawnActor<ATestActor>(
ATestActor::StaticClass(),
GetActorLocation(),
FRotator::ZeroRotator,
SpawnParams
);
}
모듈 결과 확인
여기까지 하면 에디터를 처음 열었을 때, 모듈의 시작로그, 에디터의 실행을 했을 때, 액터의 BeginPlay 로그가 찍혀야 한다.

정상적으로 로그가 나오는 모습을 확인할 수 있다.
Temporary 플러그인 만들기
모듈과 플러그인의 차이에는 재사용성에 있다.
모듈은 프로젝트 안에 종속되지만, 플러그인은 독립적인 구조를 가져서 다른 프로젝트에서도 쓸 수 있다.
이번엔 플러그인 폴더를 만들어 본다.
플러그인 폴더 구조 생성
프로젝트 폴더에 Plugins폴더를 만들고 내부를 다음과 같이 구성한다.
Plugins/
└── Temporary/
├── Content/
├── Source/
│ └── Temporary/
│ ├── Temporary.Build.cs
│ ├── Temporary.h
│ └── Temporary.cpp
└── Temporary.uplugin
Temporary.uplugin 작성
플러그인의 메타데이터를 JSON형식으로 기입하는 파일이다.
이 파일이 있어야 언리얼이 폴더를 플러그인으로 인식한다.

CanContatinContent 를 true로 설정해야 콘텐츠 브라우저에서 플러그인 폴더가 보인다.
플러그인 모듈 파일 작성
모듈 구조는 Test모듈과 동일하다.
Temporary.Build.cs

PublcIncludePaths.Add(ModuleDirectory); 는 이후에 나올 include 경로의 문제때문에 이를 해결하면서 추가했다.
Temporary.h

Temporary.cpp

.uproject에 플러그인 등록
기존 uproject 파일에서 Plugins 항목에 Temporary를 추가했다.

플러그인 활용 - CharacterData클래스
Temporary 플러그인 안에 UCharacterData 클래스를 만들어 캐릭터의 데이터를 저장하게 하고, 주 모듈의 캐릭터에서 해당 데이터를 출력해보려고 한다.
UCharacterData.h

UCharacterData.cpp

UObject를 상속받는 이유는 가비지컬렉터가 메모리를 자동 관리하고, UPROPERTY 매크로를 사용할 수 있기 때문이다.
단순 struct나 일반 class로는 이런 기능을 사용할 수 없다.
캐릭터에서 Data 사용
// HW10Character.h
#include "CharacterData.h"
// 클래스 안에 변수 선언
UPROPERTY()
TObjectPtr<UCharacterData> CharacterData;
// HW10Character.cpp BeginPlay
void AHW10Character::BeginPlay()
{
Super::BeginPlay();
CharacterData = NewObject<UCharacterData>(this);
if (IsValid(CharacterData))
{
FString Message = FString::Printf(
TEXT("=== CharacterData: Name: %s | HP: %.0f | Speed: %.0f | Level: %d ==="),
*CharacterData->CharacterName,
CharacterData->MaxHealth,
CharacterData->MoveSpeed,
CharacterData->Level
);
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Yellow, Message);
UE_LOG(LogTemp, Warning, TEXT("%s"), *Message);
}
}
이렇게 하고 실행하면 정확히 로그가 출력되어야 한다.
트러블슈팅 - include 경로를 찾지 못하는 문제
HW10Character.cpp 부분에서 에러가 발생했다.
Error C1083: Cannot open include file: 'CharacterData.h': No such file or directory
이 오류의 원인은 HW10 모듈이 Temporary 플러그인의 헤더 파일 경로를 알지 못해서 나오는 오류이다.
다음 두 가지를 수정해서 해결했다.
Temporary.Build.cs에 include 경로 추가
using System.IO; // 추가
// Build.cs 생성자 안에 추가
PublicIncludePaths.Add(ModuleDirectory);
아까 Build.cs 부분에서 잠깐 나왔던 부분이다.
ModuleDirectory는 Build.cs가 있는 폴더의 절대 경로를 자동으로 반환하는 내장변수이다.
이렇게 하면 이 모듈에 의존하는 다른 모듈들도 해당 경로를 include 경로로 사용할 수 있다.
HW10.Build.cs에 Temporary 의존성 추가
PublicDependencyModuleNames.AddRange(new string[]
{
"Core", "CoreUObject", "Engine", "InputCore",
"EnhancedInput", "Test",
"Temporary" // 추가
});
최종 결과

모든 설정이 완료된 후 에디터를 켜고, PIE를 실행했을 때의 Output Log이다. 문제없이 잘 출력되는 모습을 확인할 수 있다.
핵심 포인트 정리
- 언리얼 모듈은 Build.cs, 헤더, cpp 세 파일이 최소 구성이다.
- 모듈을 추가하면 Target.cs와 .uproject 두 곳에 등록해야 빌드 대상이 된다.
- LoadingPhase: PreDefault는 주 모듈보다 먼저 로드되어야 하는 모듈에 사용한다.
- StartupModule()은 에디터 시작 시 실행된다.
- 플러그인은 .uplugin 파일이 있어야 언리얼이 플러그인으로 인식한다.
- API매크로는 파일이 속한 모듈의 것을 사용해야 한다.
- 다른 모듈의 헤더를 include 하려면 PublicIncludePaths와 PublicDependencyModuleNames 두 곳에 등록해야 한다.
- UObject를 상속받아야 NewObject<> , UPROPERTY(), 가비지컬렉션 자동 관리를 사용할 수 있다.
'Unreal' 카테고리의 다른 글
| <언리얼> IK Rig 세팅 (1) | 2026.05.30 |
|---|---|
| <언리얼> 애니메이션 리타겟팅(UE5) (0) | 2026.05.17 |
| <언리얼 C++> RandRange와 VRandCone의 차이 (0) | 2026.05.07 |
| < UE5 > 레벨 진행 시스템 - GameStateClass (1) | 2026.04.28 |
| < 언리얼 C++ > 6자유도 비행체 + 중력 / 낙하 + 에어 컨트롤 구현 (0) | 2026.04.22 |