[Project OnlyOne] Server Lobby UI 구현
Unreal Engine 5 멀티플레이어 게임의 서버 로비 시스템에서 플레이어 관리 기능을 구현했습니다. 플레이어의 입장, 퇴장, 준비 상태 관리를 동적으로 처리하는 UI 입니다.
[Project OnlyOne] Server Lobby UI 구현
Unreal Engine 5 멀티플레이어 게임의 서버 로비 시스템에서 플레이어 관리 기능을 구현했습니다. 플레이어의 입장, 퇴장, 준비 상태 관리를 동적으로 처리하는 UI 입니다.
플레이어 슬롯 동적 생성 및 관리
플레이어의 인원 수 만큼, 플레이어의 정보를 나타내는 UI가 필요합니다. 서버 로비에 플레이어가 입장할 때마다 동적으로 플레이어 슬롯 UI를 생성하고 관리하는 시스템을 구현했습니다.
1. 플레이어 입장 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void UPOServerLobbyWidget::OnJoinPlayer(FJoinServerData& InNewPlayer)
{
if (!PlayerSlotClass)
{
UE_LOG(POLog, Warning, TEXT("PlayerSlotClass is not set!"));
return;
}
FString PlayerKey = InNewPlayer.Name;
if (PlayerSlots.Contains(PlayerKey))
{
UE_LOG(POLog, Warning, TEXT("Player slot already exists for key: %s"), *PlayerKey);
return;
}
if (UPOServerLobbyPlayerElementWidget* NewPlayerSlot = CreateWidget<UPOServerLobbyPlayerElementWidget>(this, PlayerSlotClass))
{
PlayerSlots.Add(PlayerKey, NewPlayerSlot);
NewPlayerSlot->AddToViewport();
NewPlayerSlot->SetPlayerName(InNewPlayer.Name);
PlayerListScrollBox->AddChild(NewPlayerSlot);
UE_LOG(POLog, Log, TEXT("Created and stored player slot for player: %s"), *PlayerKey);
}
else
{
UE_LOG(POLog, Error, TEXT("Failed to create player slot widget"));
}
}
핵심 포인트
- TMap<FString, TObjectPtr
> PlayerSlots를 사용한 플레이어 슬롯 관리 - 플레이어 이름을 키로 사용하여 중복 방지
- CreateWidget을 통한 동적 위젯 생성
- ScrollBox에 자동으로 추가하여 UI 업데이트
2. 플레이어 퇴장 처리
플레이어가 로비를 떠날 때 해당 플레이어의 UI 슬롯을 안전하게 제거하는 기능을 구현했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void UPOServerLobbyWidget::OnExitPlayer(FJoinServerData& InExitPlayer)
{
if (PlayerSlots.Contains(InExitPlayer.Name))
{
if (UPOServerLobbyPlayerElementWidget* PlayerSlot = PlayerSlots[InExitPlayer.Name])
{
PlayerSlot->RemoveFromParent();
PlayerSlots.Remove(InExitPlayer.Name);
UE_LOG(POLog, Log, TEXT("Removed player slot for player: %s"), *InExitPlayer.Name);
}
}
else
{
UE_LOG(POLog, Warning, TEXT("No player slot found for player: %s"), *InExitPlayer.Name);
}
}
핵심 포인트
- 메모리 누수 방지를 위한 적절한 위젯 제거
RemoveFromParent()를 통한 UI 계층에서의 안전한 제거- 맵에서도 동시에 제거하여 데이터 일관성 유지
3. 플레이어 준비 상태 관리
각 플레이어의 준비 상태를 실시간으로 업데이트하는 시스템을 구현했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void UPOServerLobbyWidget::OnReadyPlayer(const FJoinServerData& InReadyPlayer, bool bIsReady)
{
if (PlayerSlots.Contains(InReadyPlayer.Name))
{
if (UPOServerLobbyPlayerElementWidget* PlayerSlot = PlayerSlots[InReadyPlayer.Name])
{
PlayerSlot->SetPlayerReadyState(bIsReady);
UE_LOG(POLog, Log, TEXT("Set ready state for player: %s to %s"), *InReadyPlayer.Name, bIsReady ? TEXT("Ready") : TEXT("Not Ready"));
}
}
else
{
UE_LOG(POLog, Warning, TEXT("No player slot found for player: %s"), *InReadyPlayer.Name);
}
}
4. 테스트 기능 구현
개발 및 디버깅을 위한 테스트 버튼 기능을 추가했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void UPOServerLobbyWidget::TestJoinButtonClicked()
{
FJoinServerData TestPlayer;
TestPlayer.Name = TEXT("Test player" + FString::FromInt(PlayerSlots.Num() + 1));
TestPlayer.IPAddress = TEXT("123456");
OnJoinPlayer(TestPlayer);
}
void UPOServerLobbyWidget::TestExitButtonClicked()
{
FJoinServerData TestPlayer;
TestPlayer.Name = TEXT("Test player" + FString::FromInt(PlayerSlots.Num()));
OnExitPlayer(TestPlayer);
}
테스트 결과
마무리
오늘 구현한 서버 로비 시스템은 멀티플레이어 게임의 핵심적인 기능 중 하나입니다. 동적 UI 생성, 안전한 메모리 관리, 이벤트 기반 아키텍처 등을 통해 확장 가능하고 유지보수하기 쉬운 시스템을 구축할 수 있었습니다.
특히 TMap을 활용한 플레이어 슬롯 관리와 CreateWidget을 통한 동적 위젯 생성 패턴은 다른 UI 시스템에서도 응용할 수 있는 유용한 기법이라고 생각합니다.
This post is licensed under CC BY 4.0 by the author.

