PART 12 · 강의 1/8

프로젝트 구조 설계

대규모 오픈월드 RPG를 위한 모듈화된 프로젝트 아키텍처

01

프로젝트 디렉토리 구조

Epic 코딩 표준 기반 폴더 구성

OpenWorldRPG/
├── Source/
│   ├── OpenWorldRPG/              # 메인 게임 모듈
│   │   ├── Public/
│   │   │   ├── Core/            # 핵심 게임 클래스
│   │   │   ├── Character/       # 캐릭터 시스템
│   │   │   ├── Combat/          # 전투 시스템
│   │   │   ├── Inventory/       # 인벤토리
│   │   │   ├── Quest/           # 퀘스트
│   │   │   └── UI/              # UI 클래스
│   │   └── Private/
│   ├── OpenWorldRPGAI/            # AI 모듈
│   ├── OpenWorldRPGNetwork/       # 네트워킹 모듈
│   └── OpenWorldRPGEditor/        # 에디터 전용 모듈
├── Content/
│   ├── Characters/
│   ├── Environments/
│   ├── Effects/
│   ├── UI/
│   └── Maps/
├── Config/
├── Plugins/
│   └── GameFeatures/
└── OpenWorldRPG.uproject
폴더 구조 원칙
  • Public/: 외부 모듈에 노출할 헤더 파일
  • Private/: 내부 전용 헤더 및 cpp 파일
  • 모듈별로 Build.cs 파일에서 의존성 관리
  • API 매크로는 필요한 클래스에만 추가
02

모듈 설계

기능별 모듈 분리

OpenWorldRPG (Runtime)

핵심 게임플레이 로직, 캐릭터, 전투, 인벤토리, UI

OpenWorldRPGAI (Runtime)

NPC AI, 적 AI, Behavior Tree, EQS

OpenWorldRPGNetwork (Runtime)

네트워킹, 복제, 세션 관리, Co-op 시스템

OpenWorldRPGEditor (Editor)

에디터 확장, 커스텀 도구, 데이터 에디터

OpenWorldRPG.Build.cs
using UnrealBuildTool; public class OpenWorldRPG : ModuleRules { public OpenWorldRPG(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; // Public 의존성 (이 모듈을 사용하는 다른 모듈도 접근) PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "GameplayAbilities", "GameplayTags", "GameplayTasks", "UMG", "Slate", "SlateCore" }); // Private 의존성 (이 모듈 내부에서만 사용) PrivateDependencyModuleNames.AddRange(new string[] { "Niagara", "AIModule", "NavigationSystem", "OnlineSubsystem", "OnlineSubsystemUtils" }); // AI 모듈 의존성 PrivateDependencyModuleNames.Add("OpenWorldRPGAI"); // 네트워킹 모듈 의존성 PrivateDependencyModuleNames.Add("OpenWorldRPGNetwork"); } }
03

핵심 클래스 설계

게임 프레임워크 클래스

C++
// OpenWorldRPGGameInstance.h #pragma once #include "CoreMinimal.h" #include "Engine/GameInstance.h" #include "OpenWorldRPGGameInstance.generated.h" /** * 게임 인스턴스 - 게임 세션 전체에서 유지되는 데이터 */ UCLASS() class OPENWORLDRPG_API UOpenWorldRPGGameInstance : public UGameInstance { GENERATED_BODY() public: virtual void Init() override; virtual void Shutdown() override; // 현재 플레이어 세이브 데이터 UPROPERTY(BlueprintReadWrite, Category = "SaveGame") TObjectPtr<UPlayerSaveData> CurrentSaveData; // 글로벌 게임 설정 UPROPERTY(BlueprintReadOnly, Category = "Settings") FGameSettings GameSettings; // 세이브/로드 UFUNCTION(BlueprintCallable, Category = "SaveGame") bool SaveGame(int32 SlotIndex); UFUNCTION(BlueprintCallable, Category = "SaveGame") bool LoadGame(int32 SlotIndex); };
C++
// OpenWorldRPGGameMode.h #pragma once #include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "OpenWorldRPGGameMode.generated.h" /** * 게임 모드 - 게임 규칙 및 플레이어 관리 */ UCLASS() class OPENWORLDRPG_API AOpenWorldRPGGameMode : public AGameModeBase { GENERATED_BODY() public: AOpenWorldRPGGameMode(); virtual void InitGame( const FString& MapName, const FString& Options, FString& ErrorMessage) override; virtual void PostLogin(APlayerController* NewPlayer) override; virtual void Logout(AController* Exiting) override; // 플레이어 리스폰 UFUNCTION(BlueprintCallable, Category = "Respawn") void RespawnPlayer(APlayerController* Player); protected: // Seamless Travel 지원 (Co-op) virtual void GetSeamlessTravelActorList( bool bToTransition, TArray<AActor*>& ActorList) override; };
C++
// OpenWorldRPGPlayerController.h #pragma once #include "CoreMinimal.h" #include "GameFramework/PlayerController.h" #include "OpenWorldRPGPlayerController.generated.h" /** * 플레이어 컨트롤러 - 입력 처리 및 UI 관리 */ UCLASS() class OPENWORLDRPG_API AOpenWorldRPGPlayerController : public APlayerController { GENERATED_BODY() public: AOpenWorldRPGPlayerController(); virtual void BeginPlay() override; virtual void SetupInputComponent() override; // UI 표시/숨김 UFUNCTION(BlueprintCallable, Category = "UI") void ShowInventory(); UFUNCTION(BlueprintCallable, Category = "UI") void ShowQuestLog(); UFUNCTION(BlueprintCallable, Category = "UI") void ShowCharacterMenu(); protected: // Enhanced Input UPROPERTY(EditDefaultsOnly, Category = "Input") TObjectPtr<UInputMappingContext> DefaultMappingContext; // HUD 위젯 UPROPERTY() TObjectPtr<UMainHUDWidget> MainHUD; };
04

Subsystem 아키텍처

매니저 패턴 대신 Subsystem 활용

C++
// QuestSubsystem.h - 퀘스트 관리 Subsystem #pragma once #include "CoreMinimal.h" #include "Subsystems/GameInstanceSubsystem.h" #include "QuestSubsystem.generated.h" UCLASS() class OPENWORLDRPG_API UQuestSubsystem : public UGameInstanceSubsystem { GENERATED_BODY() public: virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; // 퀘스트 수락 UFUNCTION(BlueprintCallable, Category = "Quest") bool AcceptQuest(FName QuestID); // 퀘스트 완료 UFUNCTION(BlueprintCallable, Category = "Quest") bool CompleteQuest(FName QuestID); // 진행 상황 업데이트 UFUNCTION(BlueprintCallable, Category = "Quest") void UpdateQuestProgress(FName QuestID, FName ObjectiveID, int32 Progress); // 이벤트 UPROPERTY(BlueprintAssignable, Category = "Quest") FOnQuestUpdated OnQuestUpdated; UPROPERTY(BlueprintAssignable, Category = "Quest") FOnQuestCompleted OnQuestCompleted; private: UPROPERTY() TMap<FName, FQuestState> ActiveQuests; }; // WorldStateSubsystem.h - 월드 상태 관리 UCLASS() class OPENWORLDRPG_API UWorldStateSubsystem : public UWorldSubsystem { GENERATED_BODY() public: virtual void OnWorldBeginPlay(UWorld& InWorld) override; // 날씨 시스템 UFUNCTION(BlueprintCallable, Category = "Weather") void SetWeather(EWeatherType NewWeather, float TransitionTime); // 시간대 UFUNCTION(BlueprintCallable, Category = "Time") void SetTimeOfDay(float Hour); // 월드 이벤트 UFUNCTION(BlueprintCallable, Category = "Events") void TriggerWorldEvent(FName EventID); private: EWeatherType CurrentWeather; float CurrentTimeOfDay; };
SUMMARY

핵심 요약

  • 모듈 분리: 게임플레이, AI, 네트워킹, 에디터를 별도 모듈로
  • Public/Private 폴더 구조로 API 경계 명확화
  • GameInstance: 세션 전체 데이터 (세이브, 설정)
  • GameMode: 게임 규칙, 플레이어 관리
  • Subsystem: 싱글톤 대신 라이프사이클 관리되는 매니저
  • Build.cs에서 모듈 의존성 명확히 정의
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: RPG 프로젝트 기본 구조 생성

C++ 기반 UE5 프로젝트를 생성하고, RPGCore, RPGCombat, RPGUI, RPGWorld 모듈로 분리하세요. 각 모듈의 Build.cs를 작성하고, 모듈 간 의존성을 최소화하여 빌드 시간을 단축하세요.

실습 2: Git 워크플로우 설정

.gitignore에 UE5 관련 파일(Intermediate, Saved, DerivedDataCache)을 추가하고, Git LFS로 대용량 에셋을 관리하세요. Feature Branch 워크플로우와 PR 리뷰 프로세스를 수립하세요.

심화 과제: 기술 설계 문서 작성

RPG 프로젝트의 핵심 시스템(전투, 인벤토리, 퀘스트, 네트워킹, 월드 스트리밍)의 기술 설계 문서를 작성하세요. 클래스 다이어그램, 시퀀스 다이어그램, 데이터 플로우를 포함하세요.