[DAY75] Game Cycle : State and Loop

베리투스·2025년 12월 2일

TIL: Today I Learned

목록 보기
64/93
post-thumbnail

이제 플레이어가 들어온 후 '대기 -> 게임 시작 -> 결판 -> 재시작'으로 이어지는 게임의 완전한 순환(Game Loop)을 만들 차례다.

오늘은 GameMode(심판)GameState(현황판)를 이용해 게임의 상태를 관리하고, 승패가 결정되면 결과 화면을 띄운 뒤 다시 타이틀로 돌아가는 전체 로직을 완성했다.


📌 오늘의 목표

  • GameModeGameState를 활용한 게임 상태(MatchState) 동기화
  • 타이머(Timer)를 이용한 게임 진행 로직 (대기 시간, 제한 시간)
  • Client RPC를 활용한 승리/패배 결과 UI 출력
  • 게임 종료 후 타이틀 화면 귀환(Client)서버 리셋

📚이론 및 원리

1. 심판과 현황판 : GameMode & GameState

멀티플레이 게임 로직의 핵심은 "누가 관리하고, 어떻게 알리는가"이다.

  • GameMode (Server Only): 게임의 심판이다. "3초 뒤 시작한다", "너 아웃", "게임 끝" 같은 판정을 내리고 타이머를 굴린다. 클라이언트에는 존재하지 않으므로 보안성이 높다.
  • GameState (Replicated): 게임의 현황판이다. 심판(GameMode)이 내린 결정(현재 상태, 남은 시간, 생존자 수)을 저장하고, 이를 모든 클라이언트에게 복제(Replication)하여 보여준다.

2. 게임의 상태 관리 (State Machine)

게임의 흐름을 체계적으로 제어하기 위해 EMatchState 열거형(Enum)을 만들고, GameState에서 이를 관리하도록 했다.

  • Waiting: 플레이어 접속 대기. 최소 인원(2명)이 모이면 카운트다운 시작.
  • Playing: 실제 게임 진행. 생존자가 1명 이하가 될 때까지 전투.
  • Ending: 결과 출력 및 서버 리셋 대기.
// [ADXGameMode.cpp] 1초마다 실행되는 타이머 루프
void ADXGameMode::UpdateGameLoop()
{
    // GameState의 상태를 보고 행동 결정
    switch (DXGameState->MatchState)
    {
    case EMatchState::Waiting:
        // 인원이 충족되면 카운트다운 -> Playing으로 전환
        if (AlivePlayers.Num() >= MinPlayers) { StartMatch(); }
        break;
        
    case EMatchState::Playing:
        // 생존자가 1명 남으면 -> Ending으로 전환
        if (AlivePlayers.Num() <= 1) { EndMatch(); }
        break;
    }
}

3. 결과 출력과 귀환 (Client RPC)

승패가 결정되는 순간, 서버는 모든 클라이언트에게 결과를 알려줘야 한다. 이때 UI는 클라이언트 고유의 영역이므로 Client RPC를 사용한다.

  1. Server: EndMatch()에서 승리자와 패배자를 구분.
  2. Server: 각 플레이어 컨트롤러의 ClientRPCShowResult(Rank) 호출.
  3. Client: RPC를 받아 UI(Win/Lose)를 띄움.
  4. Timer: 5초 뒤 클라이언트는 OpenLevel("Title")을 실행해 스스로 나감.
  5. Server: 모두가 나가면 OpenLevel(CurrentMap)을 실행해 방을 초기화(Reset).
// [PlayerController.cpp]
void ADXPlayerController::ClientRPCShowResult_Implementation(bool bIsWinner)
{
    // 로컬에서만 UI 생성
    if (IsLocalController())
    {
        UUserWidget* ResultWidget = CreateWidget...(ResultWidgetClass);
        ResultWidget->SetText(bIsWinner ? "VICTORY" : "DEFEAT");
        ResultWidget->AddToViewport();
    }
    
    // 잠시 후 타이틀로 이동 (SetTimer 활용)
}

✅ 핵심 요약

클래스역할주요 로직
GameMode[Server] 관리자UpdateGameLoop(타이머), 상태 변경(SetMatchState)
GameState[Rep] 데이터MatchState(Waiting/Playing/Ending) 변수 동기화
Client RPC[To Client] 명령ShowResultUI: 서버가 클라에게 "결과창 띄워" 명령
Game Loop흐름 제어Title \rightarrow Lobby \rightarrow Play \rightarrow Result \rightarrow Title
profile
Shin Ji Yong // Unreal Engine 5 공부중입니다~

0개의 댓글