
이제 플레이어가 들어온 후 '대기 -> 게임 시작 -> 결판 -> 재시작'으로 이어지는 게임의 완전한 순환(Game Loop)을 만들 차례다.
오늘은 GameMode(심판)와 GameState(현황판)를 이용해 게임의 상태를 관리하고, 승패가 결정되면 결과 화면을 띄운 뒤 다시 타이틀로 돌아가는 전체 로직을 완성했다.
MatchState) 동기화Timer)를 이용한 게임 진행 로직 (대기 시간, 제한 시간)멀티플레이 게임 로직의 핵심은 "누가 관리하고, 어떻게 알리는가"이다.
게임의 흐름을 체계적으로 제어하기 위해 EMatchState 열거형(Enum)을 만들고, GameState에서 이를 관리하도록 했다.
// [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;
}
}
승패가 결정되는 순간, 서버는 모든 클라이언트에게 결과를 알려줘야 한다. 이때 UI는 클라이언트 고유의 영역이므로 Client RPC를 사용한다.
EndMatch()에서 승리자와 패배자를 구분.ClientRPCShowResult(Rank) 호출.OpenLevel("Title")을 실행해 스스로 나감.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 Lobby Play Result Title |