UE5 Modular Gameplay Plugin — 게임플레이 기능 분리
Modular Gameplay Plugin은 UE5(Lyra 프로젝트에서 채용)의 게임플레이 기능을 독립 플러그인(GameFeature Plugin)으로 분리하는 아키텍처입니다. 각 기능(무기 시스템, 스킬, 게임 모드)을 독립적으로 활성화/비활성화할 수 있어 DLC, 라이브 서비스, 멀티플레이어 모드 전환에 적합합니다.
1. 플러그인 활성화
섹션 제목: “1. 플러그인 활성화”Edit → Plugins → Gameplay → ModularGameplay → EnableEdit → Plugins → Gameplay → GameFeatures → Enable2. GameFeature Plugin 생성
섹션 제목: “2. GameFeature Plugin 생성”Tools → New Plugin → Game FeaturePlugin Name: WeaponSystem생성 구조:
Plugins/GameFeatures/WeaponSystem/├── WeaponSystem.uplugin├── Source/WeaponSystem/└── Content/.uplugin 설정:
{ "FileVersion": 3, "Version": 1, "VersionName": "1.0", "FriendlyName": "WeaponSystem", "GameFeatureData": "WeaponSystem/WeaponSystemData.uasset"}3. GameFeatureData — 기능 정의
섹션 제목: “3. GameFeatureData — 기능 정의”에디터에서 GameFeatureData 에셋 생성 후 Action 추가:
// C++로 커스텀 GameFeature Action 정의UCLASS()class UGameFeatureAction_AddAbilities : public UGameFeatureAction{ GENERATED_BODY()public: UPROPERTY(EditAnywhere) TArray<FGameplayAbilitySpec> AbilitiesToAdd;
virtual void OnGameFeatureActivating( FGameFeatureActivatingContext& Context) override { // 플레이어에게 어빌리티 추가 for (auto* Player : Context.GetPlayers()) { auto* ASC = Player->GetAbilitySystemComponent(); for (auto& Spec : AbilitiesToAdd) ASC->GiveAbility(Spec); } }
virtual void OnGameFeatureDeactivating( FGameFeatureDeactivatingContext& Context) override { // 어빌리티 제거 for (auto* Player : Context.GetPlayers()) { auto* ASC = Player->GetAbilitySystemComponent(); ASC->ClearAllAbilities(); } }};4. 런타임 GameFeature 활성화/비활성화
섹션 제목: “4. 런타임 GameFeature 활성화/비활성화”#include "GameFeaturesSubsystem.h"
// GameFeature 활성화void AMyGameMode::ActivateWeaponSystem(){ UGameFeaturesSubsystem& Subsystem = UGameFeaturesSubsystem::Get();
FString PluginURL = TEXT("/WeaponSystem/WeaponSystem.uplugin");
Subsystem.LoadAndActivateGameFeaturePlugin( PluginURL, FGameFeaturePluginChangeStateComplete::CreateLambda( [](const UE::GameFeatures::FResult& Result) { if (Result.HasValue()) UE_LOG(LogTemp, Log, TEXT("WeaponSystem 활성화 성공")); else UE_LOG(LogTemp, Error, TEXT("활성화 실패: %s"), *Result.GetError()); }));}
// GameFeature 비활성화void AMyGameMode::DeactivateWeaponSystem(){ FString PluginURL = TEXT("/WeaponSystem/WeaponSystem.uplugin");
UGameFeaturesSubsystem::Get().DeactivateGameFeaturePlugin( PluginURL, FGameFeaturePluginChangeStateComplete());}5. Component 주입 — AddComponents Action
섹션 제목: “5. Component 주입 — AddComponents Action”에디터의 GameFeatureData에 AddComponents Action 추가:
// GameFeature 활성화 시 지정 Actor에 Component 자동 추가UCLASS()class UGameFeatureAction_AddComponents : public UGameFeatureAction{ GENERATED_BODY()public: UPROPERTY(EditAnywhere) TSoftClassPtr<UActorComponent> ComponentClass;
UPROPERTY(EditAnywhere) TSoftClassPtr<AActor> ActorClass; // 대상 Actor 타입
virtual void OnGameFeatureActivating( FGameFeatureActivatingContext& Context) override { // 현재 월드의 해당 Actor 타입에 Component 추가 for (TActorIterator<AActor> It(Context.GetWorld(), ActorClass.LoadSynchronous()); It; ++It) { (*It)->AddComponentByClass( ComponentClass.LoadSynchronous(), false, FTransform(), false); } }};6. GameFeature 상태 머신
섹션 제목: “6. GameFeature 상태 머신”Unregistered → Registered → Loaded → Active ↑ | └──────────── Deactivated ─────────┘// 현재 상태 확인EGameFeaturePluginState State = UGameFeaturesSubsystem::Get().GetPluginState(PluginURL);7. Lyra 프로젝트 구조 참고
섹션 제목: “7. Lyra 프로젝트 구조 참고”Plugins/GameFeatures/├── ShooterCore/ ← 핵심 FPS 기능├── ShooterMaps/ ← 맵별 설정├── TopDownArena/ ← 탑다운 모드└── PerfTests/ ← 성능 테스트 모드각 GameFeature는 독립 플러그인으로 필요할 때만 로드됩니다.
8. UGameFrameworkComponentManager — Extension Point 패턴
섹션 제목: “8. UGameFrameworkComponentManager — Extension Point 패턴”Lyra가 사용하는 Extension Point 패턴으로 GameFeature가 코어 Actor를 직접 참조하지 않고도 컴포넌트를 주입합니다.
#include "Components/GameFrameworkComponentManager.h"
// 코어 Actor에서: Extension Point 등록void AMyCharacter::BeginPlay(){ Super::BeginPlay();
// 이 액터가 "MyCharacter" 확장 포인트를 노출함을 선언 UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);}
void AMyCharacter::EndPlay(const EEndPlayReason::Type Reason){ UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this); Super::EndPlay(Reason);}
// GameFeature Action에서: 코어 Actor에 컴포넌트 주입UCLASS()class UGameFeatureAction_AddWeaponSlot : public UGameFeatureAction{ GENERATED_BODY()
UPROPERTY(EditAnywhere) TSoftClassPtr<UActorComponent> WeaponSlotComponentClass;
virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& Context) override { UGameFrameworkComponentManager* Manager = UGameInstance::GetSubsystem<UGameFrameworkComponentManager>( Context.GetGameInstance());
// "MyCharacter" 수신자 액터에 WeaponSlotComponent를 자동 추가 Manager->AddComponentRequest( AMyCharacter::StaticClass(), WeaponSlotComponentClass); }
virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context) override { UGameFrameworkComponentManager* Manager = UGameInstance::GetSubsystem<UGameFrameworkComponentManager>( Context.GetGameInstance());
Manager->RemoveComponentRequest( AMyCharacter::StaticClass(), WeaponSlotComponentClass); }};Extension Point 흐름:
AMyCharacter::BeginPlay→AddGameFrameworkComponentReceiver호출- 이미 활성화된 GameFeature가 있으면
WeaponSlotComponent즉시 주입 - 이후 GameFeature 활성화 → 월드의 모든 수신자 액터에 자동 주입
- GameFeature 비활성화 → 주입된 컴포넌트 자동 제거
Modular Gameplay는 게임플레이 기능을 플러그인 단위로 캡슐화해 코어 게임과 완전히 분리합니다. DLC 기능, 시즌 콘텐츠, 게임 모드 전환을 런타임에 플러그인 활성화/비활성화로 처리할 수 있어 라이브 서비스 게임에 특히 효과적입니다. Lyra 프로젝트를 레퍼런스로 삼아 구조를 파악하면 빠르게 적용할 수 있습니다.