맵 이동과 ServerTravel 기초
27강. 맵 이동과 ServerTravel 기초
1. 이번 강의에서 해결할 문제
호스트가 OpenLevel로 경기 맵을 열자 참가자는 로비에 남거나 연결이 끊깁니다. 클라이언트가 각자 같은 맵을 열어도 같은 서버 World로 이동한 것이 아닙니다. 멀티플레이 맵 전환은 서버가 ServerTravel을 시작하고 연결된 클라이언트를 함께 이동시켜야 합니다.
2. 학습 목표
3. 핵심 개념
서버 UWorld::ServerTravel은 서버 World를 새 맵으로 바꾸고 연결된 클라이언트를 따라오게 합니다. 클라이언트의 APlayerController::ClientTravel은 세션 참가 뒤 새 서버 주소로 연결할 때 사용합니다. 일반 클라이언트가 ServerTravel을 시작할 수 없습니다.
Seamless Travel은 작은 Transition Map을 거쳐 연결 중단을 줄이지만 모든 Actor가 자동 유지되는 것은 아닙니다. PlayerState 복사와 Controller 유지 정책, GameMode의 HandleSeamlessTravelPlayer, 필요한 GetSeamlessTravelActorList를 이해해야 합니다. 경기 GameState와 Pawn은 새 맵 규칙에 맞게 다시 만들어지는 편이 명확합니다.
4. 단계별 실습
ACaptureLobbyGameMode::ACaptureLobbyGameMode()
{
bUseSeamlessTravel = true;
}
void ACaptureLobbyGameMode::TryStartMatch()
{
if (!HasAuthority() || bTravelStarted) return;
const ACaptureArenaGameState* GS = GetGameState<ACaptureArenaGameState>();
if (!GS || GS->PlayerArray.Num() != 2) return;
for (const APlayerState* BaseState : GS->PlayerArray)
{
const ACaptureArenaPlayerState* PS =
Cast<ACaptureArenaPlayerState>(BaseState);
if (!PS || !PS->IsReady()) return;
}
bTravelStarted = true;
GetWorld()->ServerTravel(TEXT("/Game/Maps/CaptureMap?listen"));
}
Project Settings → Maps & Modes에서 Transition Map을 작고 의존성이 적은 맵으로 설정합니다. LobbyMap과 CaptureMap이 Cook/Package 대상에 포함되는지도 확인합니다. ?listen은 호스트 World가 리슨 서버로 열려야 하는 최초 경로에서 사용하며 이미 서버인 상황과 URL 옵션을 기록합니다.
검증 순서
- 별도 프로세스 리슨 서버에 두 클라이언트가 접속합니다.
- 한 명만 Ready일 때 Travel이 거부되는지 확인합니다.
- 둘 다 Ready면 서버 로그에서 Lobby → Transition → CaptureMap을 추적합니다.
- 각 PlayerState의 TeamId가 유지되고 Pawn·GameState가 경기 맵에서 새로 만들어지는지 확인합니다.
- PIE 제약이 의심되면 패키지 또는 Standalone 별도 프로세스로 재검증합니다.
5. 코드가 동작하는 이유
로비 GameMode는 서버에만 있어 준비 인원과 Travel 중복을 권위 있게 검사합니다. ServerTravel이 연결된 플레이어를 같은 새 World로 이동시키므로 각 클라이언트의 OpenLevel 호출보다 일관됩니다. bTravelStarted는 Ready OnRep나 중복 버튼이 같은 프레임에 여러 Travel을 시작하는 것을 막습니다.
6. 자주 하는 실수와 해결법
7. 직접 실습
8. 이해 점검 질문 3개
9. 핵심 요약
맵 이동과 ServerTravel 기초 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.