콘텐츠로 이동

UE5 Gameplay Framework 구조 완전 이해

Unreal Engine의 Gameplay Framework는 게임 규칙과 플레이어 상호작용을 체계화하는 클래스 계층입니다. 각 클래스의 역할과 생성 순서를 이해하면 기능을 올바른 위치에 배치할 수 있습니다.


클래스존재 위치주요 역할
AGameModeBase서버 전용게임 규칙, 플레이어 스폰 정책
AGameStateBase서버 + 모든 클라이언트게임 공유 상태 (점수, 타이머)
APlayerController서버 + 해당 클라이언트입력 처리, 카메라 제어
APlayerState서버 + 모든 클라이언트플레이어별 공개 상태 (이름, 점수)
APawn / ACharacter서버 + 모든 클라이언트월드 내 표현(물리, 렌더링)

MyGameMode.h
UCLASS()
class AMyGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AMyGameMode();
// 플레이어 스폰 위치 결정
virtual AActor* FindPlayerStart_Implementation(
AController* Player, const FString& IncomingName) override;
// 플레이어 사망 처리
void OnPlayerDied(AController* Controller);
// 승리 조건 체크
void CheckWinCondition();
private:
int32 FragLimit = 10;
};
// MyGameMode.cpp
AMyGameMode::AMyGameMode()
{
DefaultPawnClass = AMyCharacter::StaticClass();
PlayerControllerClass = AMyPlayerController::StaticClass();
GameStateClass = AMyGameState::StaticClass();
PlayerStateClass = AMyPlayerState::StaticClass();
}

UCLASS()
class AMyGameState : public AGameStateBase
{
GENERATED_BODY()
public:
UPROPERTY(Replicated)
int32 BlueTeamScore;
UPROPERTY(Replicated)
int32 RedTeamScore;
UPROPERTY(Replicated)
float RemainingTime;
virtual void GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};
void AMyGameState::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMyGameState, BlueTeamScore);
DOREPLIFETIME(AMyGameState, RedTeamScore);
DOREPLIFETIME(AMyGameState, RemainingTime);
}

4. PlayerController — 입력과 카메라

섹션 제목: “4. PlayerController — 입력과 카메라”
UCLASS()
class AMyPlayerController : public APlayerController
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
virtual void SetupInputComponent() override;
public:
// 서버 RPC — 공격 요청
UFUNCTION(Server, Reliable)
void ServerRequestAttack();
// 클라이언트 RPC — HUD 갱신
UFUNCTION(Client, Reliable)
void ClientUpdateHUD(int32 NewHealth);
};
void AMyPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
if (UEnhancedInputComponent* EIC =
Cast<UEnhancedInputComponent>(InputComponent))
{
EIC->BindAction(AttackAction, ETriggerEvent::Triggered,
this, &AMyPlayerController::ServerRequestAttack);
}
}

5. PlayerState — 플레이어 공개 정보

섹션 제목: “5. PlayerState — 플레이어 공개 정보”
UCLASS()
class AMyPlayerState : public APlayerState
{
GENERATED_BODY()
public:
UPROPERTY(Replicated)
int32 Kills;
UPROPERTY(Replicated)
int32 Deaths;
UPROPERTY(Replicated)
FString TeamName;
void AddKill();
void AddDeath();
};

1. GameMode 생성 (서버 전용)
2. GameState 생성 및 복제 시작
3. 플레이어 접속 → PlayerController 생성
4. PlayerState 생성 및 복제
5. GameMode::SpawnDefaultPawnFor() → Pawn 스폰
6. PlayerController::Possess(Pawn)

"이 데이터가 모든 클라이언트에 필요한가?"
→ Yes: GameState 또는 PlayerState
→ No (해당 플레이어만): PlayerController
"이것은 게임 규칙인가?"
→ Yes: GameMode (서버 전용)
"이것은 물리/시각 표현인가?"
→ Yes: Pawn / Character

Gameplay Framework는 “누가 이 정보를 알아야 하는가”를 기준으로 설계되었습니다. GameMode는 규칙을 강제하고, GameState/PlayerState는 모든 클라이언트와 상태를 공유하며, PlayerController는 해당 플레이어의 입력과 UI를 담당합니다. 기능을 올바른 클래스에 배치해야 네트워크 복제가 자연스럽게 동작합니다.