Unreal Engine의 Gameplay Framework는 게임을 구성하는 주요 객체들의 책임, 수명, 복제 범위를 분리하기 위해 설계되어 있다.
| 구분 | 클래스 |
|---|---|
| 서버에만 존재 | AGameMode |
| 서버와 모든 클라이언트에 복제 | AGameState, APlayerState, APawn |
| 서버와 소유 클라이언트에 존재 | APlayerController |
| 로컬 클라이언트 전용 | AHUD, UUserWidget |
핵심 클래스
| 클래스 | 역할 |
|---|---|
UGameInstance |
게임 실행 전체 동안 유지되는 객체. 레벨 전환 후에도 살아남는 데이터와 Subsystem을 관리한다. |
AGameMode |
게임 규칙을 결정한다. 승패 판정, 매치 시작/종료, 스폰 규칙 등을 담당하며 서버에만 존재한다. |
AGameState |
클라이언트도 알아야 하는 게임 공통 상태를 저장하고 복제한다. |
APlayerController |
플레이어의 입력, 카메라, UI, Pawn 조종을 담당한다. |
AAIController |
AI가 Pawn을 조종할 때 사용하는 Controller다. Behavior Tree, Blackboard, Perception 등을 다룬다. |
APlayerState |
플레이어의 이름, 점수, 팀, 핑처럼 Pawn이 죽어도 유지되어야 하는 정보를 저장한다. |
APawn / ACharacter |
월드 안에서 실제로 존재하고 움직이는 몸체다. 사람형 캐릭터는 보통 ACharacter를 사용한다. |
AHUD |
로컬 전용 2D 화면 그리기 객체다. 현대 UE에서는 주로 UMG/Common UI가 UI의 중심이다. |
APlayerCameraManager |
최종 카메라 위치, 회전, FOV, 카메라 셰이크 등을 결정한다. |
UWorld / ULevel |
현재 실행 중인 월드와 디스크에 저장된 맵 단위. |
핵심 클래스의 책임 분리
| 책임 | 위치 |
|---|---|
| 게임 규칙, 승패 판정 | AGameMode |
| 클라이언트가 봐야 하는 매치 정보 | AGameState |
| 플레이어 개인 영구 정보 | APlayerState |
| 레벨 전환 후에도 유지되어야 하는 정보 | UGameInstance 또는 UGameInstanceSubsystem |
class ASuperPlayer : public APawn
{
float Health = 100.0f;
int32 Score = 0;
float GameTimeRemaining = 300.0f;
bool bGameStarted = false;
void UpdateHealthBar();
void CheckWinCondition();
};
이 구조는 다음과 같은 문제가 있다.
- 플레이어 개인 정보, 게임 전체 상태, UI, 게임 규칙이 한 클래스에 섞여 있다.
- Pawn이 GameMode, GameState, UI 역할까지 떠안는다.
- 멀티플레이 확장이 어렵다.
- Pawn이 죽거나 재생성될 때 점수 같은 영구 데이터가 사라질 수 있다.
GameMode
현재 레벨의 게임 규칙을 정의하는 클래스
- 어떤 Pawn을 사용할지 결정
- 플레이어 스폰 규칙 결정
- 매치 시작과 종료 관리
- 승리/패배 조건 판단
- 게임 흐름 제어
GameMode는 서버에만 존재한다.
클라이언트가 직접 봐야 하는 정보는 GameState에 넘겨야 한다.
GameModeBase와 GameMode
| 클래스 | 특징 |
|---|---|
AGameModeBase |
가벼운 기본형. 단순한 게임에 적합 |
AGameMode |
매치 상태 머신, 자동 리스폰, 관전자 모드 등을 포함 |
AGameMode를 사용할 경우 AGameState와 함께 사용AGameModeBase를 사용할 경우 AGameStateBase와 함께 사용
GameState
AGameState는 클라이언트도 봐야 하는 게임 공통 정보를 저장하는 클래스다.
- 남은 시간
- 현재 라운드
- 매치 진행 상태
- 전체 목표 진행도
GameMode, GameState 책임 분리
GameMode는 결정만 내리고 공유 정보는 GameState에 위임
GameMode가 상태를 계산한다.GameMode가GameState에 정보를 전달한다.GameState는 해당 정보를 복제한다.- UI는
GameState를 읽어서 표시한다.
UCLASS()
class AMyGameState : public AGameStateBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_RemainingTime)
float RemainingTime = 0.0f;
UFUNCTION()
void NotifyMatchStarted(float Duration);
protected:
UFUNCTION()
void OnRep_RemainingTime();
};
클라이언트가 직접 GameState의 값을 수정하는 구조는 피해야 한다.
PlayerState
APlayerState는 플레이어 한 명의 영구 상태를 저장한다.
- 플레이어 이름
- 점수
- 팀
- 핑
- 킬/데스
- 캐릭터가 죽어도 유지되어야 하는 진행 정보
Pawn은 죽거나 교체될 수 있지만, PlayerState는 플레이어의 상태를 유지하기 위해 존재한다.
| 데이터 | 적절한 위치 |
|---|---|
| 현재 체력 | APawn 또는 체력 컴포넌트 |
| 현재 무기 장착 상태 | APawn 또는 인벤토리/장비 컴포넌트 |
| 점수 | APlayerState |
| 팀 | APlayerState |
| 닉네임 | APlayerState |
| 레벨 전환 후 누적 점수 | APlayerState 또는 UGameInstance |
클라이언트에서 점수를 변경해야 한다면 직접 수정하지 말고 서버 RPC를 통해 요청해야 한다.
UFUNCTION(Server, Reliable)
void Server_AddScore(int32 Points);
GameInstance
UGameInstance는 게임 실행 시작부터 종료까지 살아 있는 객체다.
레벨이 바뀌어도 파괴되지 않는다.
- 플레이어 프로필
- 세이브 데이터
- 누적 진행도
- 전체 레벨 진행 상태
- 레벨 전환 제어
- 게임 전체에서 유지되어야 하는 매니저 기능
UCLASS()
class UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite)
FString PlayerName = TEXT("Player");
UPROPERTY(BlueprintReadWrite)
int32 TotalScore = 0;
UFUNCTION(BlueprintCallable)
void LoadNextLevel();
};
단, GameInstance에 모든 것을 몰아넣으면 사실상 전역 변수처럼 변질된다.
가능하면 데이터의 수명에 맞춰 더 좁은 스코프의 Subsystem을 사용하는 것이 좋다.
| Subsystem | 사용 상황 |
|---|---|
UEngineSubsystem |
엔진 전체에서 공유되는 기능 |
UGameInstanceSubsystem |
게임 세션 전체에서 유지되는 기능 |
UWorldSubsystem |
특정 World 안에서만 필요한 기능 |
ULocalPlayerSubsystem |
특정 로컬 플레이어에게만 필요한 기능 |
Controller
AController는 Pawn을 소유하고 조종하는 객체다.AController를 상속받는 APlayerController 또는 AAIController를 사용한다.
APlayerController
사람 플레이어 한 명의 의지를 표현한다.
- 입력 처리
- Pawn Possess / UnPossess
- 카메라 제어
- UI 생성과 관리
- PlayerState 접근
주의할 점은 PlayerController에 캐릭터의 체력, 공격력, 인벤토리 같은 물리적 게임플레이 데이터를 넣지 않는 것이다.
입력과 UI는 PlayerController, 실제 이동과 전투는 Pawn 또는 ActorComponent가 담당하는 것이 좋다.
AAIController
AI가 Pawn을 조종할 때 사용하는 Controller다.
주요 책임은 다음과 같다.
- Behavior Tree 실행
- Blackboard 관리
- AI Perception 처리
- State Tree 실행
- AI Pawn Possess
여러 적이 같은 Pawn 클래스를 사용하더라도, 각 적은 자기만의 AIController 인스턴스를 가질 수 있다.
APawn
APawn은 Controller가 Possess할 수 있는 Actor다.
조종 가능한 월드 내 물리적 존재.
- 차량
- 비행기
- 탱크
- 드론
- 추상적인 조종 대상
이동은 보통 별도의 Movement Component를 통해 처리한다.
ACharacter
ACharacter는 사람형 캐릭터를 위한 Pawn의 특수 형태다.
기본으로 다음 기능이 포함되어 있다.
UCapsuleComponentUSkeletalMeshComponentUCharacterMovementComponent- 걷기, 점프, 낙하, 수영, 비행 이동 모드
사람형 플레이어 캐릭터나 일반적인 인간형 적은 대부분 ACharacter를 상속한다.
책임 경계
Pawn이나 Character에는 다음처럼 월드 내 물리적 존재와 직접 관련된 데이터를 둔다.
- 현재 체력
- 현재 위치
- 이동 상태
- 장착 중인 무기
- 애니메이션 상태
하지만 전투, 인벤토리, 퀘스트, 스탯 등 기능이 커지면 Character에 모두 넣지 말고 컴포넌트로 분리해야 한다.
UCombatComponent* CombatComponent;
UInventoryComponent* InventoryComponent;
UStatComponent* StatComponent;
AHUD, UMG, Common UI
AHUD는 과거 방식의 2D 화면 그리기 객체다.Canvas를 이용해 크로스헤어, 디버그 텍스트, 간단한 오버레이를 그리는 용도로 사용할 수 있다.
현대 Unreal Engine에서는 대부분의 UI를 UUserWidget 기반의 UMG로 제작한다.
| 방식 | 용도 |
|---|---|
AHUD |
단순 디버그 표시, 크로스헤어, 즉시 모드 2D 그리기 |
| UMG | 일반적인 게임 UI |
| Common UI | 입력 모드, 위젯 스택, 게임패드/키보드/마우스 통합 UI 관리 |
작은 프로젝트라면 UMG만으로도 충분하다.
하지만 모달, 팝업 스택, 게임패드 지원, 입력 모드 전환이 많아지면 Common UI 도입을 고려할 수 있다.
PlayerCameraManager
APlayerCameraManager는 PlayerController가 소유하며, 최종 카메라 상태를 결정한다.
- ViewTarget 결정
- FOV 변경
- 카메라 셰이크
- 카메라 블렌딩
- 시점 전환
Pawn에 붙은 UCameraComponent가 기본 시점을 제공하고, PlayerCameraManager는 최종적으로 화면에 어떤 뷰를 보여줄지 결정한다.
UWorld, ULevel
UWorld는 현재 실행 중인 월드의 런타임 컨테이너다.
GameMode, GameState, PlayerController, Pawn, Actor 등은 모두 특정 World 안에 존재한다.
ULevel은 디스크에 저장된 .umap 파일 단위다.
하나의 World는 Persistent Level과 여러 Sub Level을 가질 수 있다.
PIE, 멀티플레이, 에디터 환경에서는 여러 World가 동시에 존재할 수 있으므로GWorld를 직접 사용하는 것을 피해야 한다.
항상 현재 객체의 컨텍스트에서 GetWorld()를 사용하는 것이 안전하다.
'Unreal Engine' 카테고리의 다른 글
| AssetManager (0) | 2026.06.19 |
|---|---|
| UE Game play Framework 2 (0) | 2026.06.18 |
| GAS 2 (0) | 2026.06.16 |
| GAS 1 (0) | 2026.06.15 |
| SmartObject 1 (0) | 2026.06.12 |