icon안동민 개발노트

게임 모드 (Game Mode)와 플레이어 컨트롤러 (Player Controller) 기초


 언리얼 엔진에서 게임 모드(Game Mode)와 플레이어 컨트롤러(Player Controller)는 게임의 규칙과 플레이어 입력을 관리하는 핵심 클래스입니다.

 이 절에서는 이들의 역할과 C++에서의 구현 방법을 살펴보겠습니다.

AGameMode 클래스

 AGameMode 클래스는 게임의 규칙, 점수 계산, 승리 조건 등을 정의합니다.

 주요 기능

  • 게임 시작과 종료 관리
  • 플레이어 스폰 위치 결정
  • 기본 폰(Pawn) 클래스 지정
  • 플레이어 컨트롤러 클래스 지정

 커스텀 게임 모드 구현

// MyGameMode.h
##pragma once
 
##include "CoreMinimal.h"
##include "GameFramework/GameModeBase.h"
##include "MyGameMode.generated.h"
 
UCLASS()
class MYGAME_API AMyGameMode : public AGameModeBase
{
    GENERATED_BODY()
 
public:
    AMyGameMode();
 
    virtual void StartPlay() override;
    virtual void Tick(float DeltaTime) override;
 
    UFUNCTION(BlueprintCallable, Category = "GameMode")
    void EndGame(bool bIsWinner);
 
private:
    float GameTime;
    bool bIsGameOver;
};
 
// MyGameMode.cpp
##include "MyGameMode.h"
##include "MyPlayerController.h"
##include "MyCharacter.h"
 
AMyGameMode::AMyGameMode()
{
    PrimaryActorTick.bCanEverTick = true;
    PlayerControllerClass = AMyPlayerController::StaticClass();
    DefaultPawnClass = AMyCharacter::StaticClass();
    GameTime = 0.0f;
    bIsGameOver = false;
}
 
void AMyGameMode::StartPlay()
{
    Super::StartPlay();
    // 게임 시작 시 초기화 로직
}
 
void AMyGameMode::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    
    if (!bIsGameOver)
    {
        GameTime += DeltaTime;
        // 게임 시간에 따른 로직 처리
    }
}
 
void AMyGameMode::EndGame(bool bIsWinner)
{
    bIsGameOver = true;
    // 게임 종료 처리 로직
}

APlayerController 클래스

 APlayerController 클래스는 플레이어의 입력을 처리하고 폰 / 캐릭터를 제어합니다.

 주요 기능

  • 플레이어 입력 처리
  • 카메라 제어
  • 폰 / 캐릭터 소유 및 제어
  • HUD 및 UI 관리

 커스텀 플레이어 컨트롤러 구현

// MyPlayerController.h
##pragma once
 
##include "CoreMinimal.h"
##include "GameFramework/PlayerController.h"
##include "MyPlayerController.generated.h"
 
UCLASS()
class MYGAME_API AMyPlayerController : public APlayerController
{
    GENERATED_BODY()
 
public:
    AMyPlayerController();
 
    virtual void SetupInputComponent() override;
 
    UFUNCTION(BlueprintCallable, Category = "Input")
    void MoveForward(float Value);
 
    UFUNCTION(BlueprintCallable, Category = "Input")
    void MoveRight(float Value);
 
    UFUNCTION(BlueprintCallable, Category = "Action")
    void StartAction();
 
protected:
    virtual void BeginPlay() override;
 
private:
    class AMyCharacter* MyCharacter;
};
 
// MyPlayerController.cpp
##include "MyPlayerController.h"
##include "MyCharacter.h"
 
AMyPlayerController::AMyPlayerController()
{
}
 
void AMyPlayerController::BeginPlay()
{
    Super::BeginPlay();
    MyCharacter = Cast<AMyCharacter>(GetPawn());
}
 
void AMyPlayerController::SetupInputComponent()
{
    Super::SetupInputComponent();
 
    InputComponent->BindAxis("MoveForward", this, &AMyPlayerController::MoveForward);
    InputComponent->BindAxis("MoveRight", this, &AMyPlayerController::MoveRight);
    InputComponent->BindAction("Action", IE_Pressed, this, &AMyPlayerController::StartAction);
}
 
void AMyPlayerController::MoveForward(float Value)
{
    if (MyCharacter)
    {
        MyCharacter->MoveForward(Value);
    }
}
 
void AMyPlayerController::MoveRight(float Value)
{
    if (MyCharacter)
    {
        MyCharacter->MoveRight(Value);
    }
}
 
void AMyPlayerController::StartAction()
{
    if (MyCharacter)
    {
        MyCharacter->StartAction();
    }
}

게임 상태 관리

 게임 상태는 주로 AGameStateBase 클래스를 상속받아 구현합니다. 이 클래스는 모든 플레이어와 관련된 게임의 전반적인 상태를 관리합니다.

// MyGameState.h
##pragma once
 
##include "CoreMinimal.h"
##include "GameFramework/GameStateBase.h"
##include "MyGameState.generated.h"
 
UCLASS()
class MYGAME_API AMyGameState : public AGameStateBase
{
    GENERATED_BODY()
 
public:
    UPROPERTY(Replicated, BlueprintReadOnly, Category = "GameState")
    int32 Score;
 
    UFUNCTION(BlueprintCallable, Category = "GameState")
    void AddScore(int32 Points);
};
 
// MyGameState.cpp
##include "MyGameState.h"
##include "Net/UnrealNetwork.h"
 
void AMyGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    DOREPLIFETIME(AMyGameState, Score);
}
 
void AMyGameState::AddScore(int32 Points)
{
    if (HasAuthority())
    {
        Score += Points;
    }
}

플레이어 생성 및 소멸 처리

 게임 모드에서 플레이어의 생성과 소멸을 관리할 수 있습니다.

// MyGameMode.h에 추가
UCLASS()
class MYGAME_API AMyGameMode : public AGameModeBase
{
    // ...
 
    virtual void PostLogin(APlayerController* NewPlayer) override;
    virtual void Logout(AController* Exiting) override;
};
 
// MyGameMode.cpp에 추가
void AMyGameMode::PostLogin(APlayerController* NewPlayer)
{
    Super::PostLogin(NewPlayer);
    // 새 플레이어 로그인 시 처리
}
 
void AMyGameMode::Logout(AController* Exiting)
{
    Super::Logout(Exiting);
    // 플레이어 로그아웃 시 처리
}

게임 모드와 플레이어 컨트롤러 간 상호작용

 게임 모드와 플레이어 컨트롤러는 서로 참조하여 상호작용할 수 있습니다.

// MyPlayerController.cpp에 추가
##include "MyGameMode.h"
 
void AMyPlayerController::SomeFunction()
{
    AMyGameMode* GameMode = Cast<AMyGameMode>(GetWorld()->GetAuthGameMode());
    if (GameMode)
    {
        GameMode->EndGame(true);
    }
}

멀티플레이어 게임에서의 역할

 멀티플레이어 게임에서 게임 모드는 서버에서만 실행되며, 플레이어 컨트롤러는 각 클라이언트와 서버에 존재합니다.

  1. 게임 모드 (서버 전용)
  • 전체 게임 규칙 관리
  • 플레이어 스폰 및 연결 관리
  • 게임 상태 업데이트 및 동기화
  1. 플레이어 컨트롤러
  • 클라이언트 : 로컬 입력 처리 및 서버로 전송
  • 서버 : 클라이언트로부터 받은 입력 검증 및 처리

 네트워크 관련 기능을 구현할 때는 RPC(Remote Procedure Calls)를 사용합니다.

// MyPlayerController.h에 추가
UFUNCTION(Server, Reliable, WithValidation)
void ServerPerformAction();
 
// MyPlayerController.cpp에 추가
void AMyPlayerController::ServerPerformAction_Implementation()
{
    // 서버에서 실행될 로직
}
 
bool AMyPlayerController::ServerPerformAction_Validate()
{
    return true; // 유효성 검사 로직
}

 게임 모드와 플레이어 컨트롤러는 언리얼 엔진의 게임플레이 프레임워크에서 핵심적인 역할을 합니다. 게임 모드를 통해 전체적인 게임 규칙과 로직을 관리하고, 플레이어 컨트롤러를 통해 개별 플레이어의 입력과 상태를 처리합니다.

 이 두 클래스를 효과적으로 활용하면 다양한 게임플레이 메커니즘을 구현할 수 있으며, 단일 플레이어 게임에서 복잡한 멀티플레이어 게임까지 확장 가능한 구조를 만들 수 있습니다.

 특히 멀티플레이어 게임을 개발할 때는 서버와 클라이언트의 역할 분담과 네트워크 동기화에 주의를 기울여야 합니다. 지속적인 테스트와 최적화를 통해 원활한 게임플레이 경험을 제공하는 것이 중요합니다.