WBP_Lobby 안에:
StartButtonReadyButton두 개 다 넣어두고, 가시성만 바꾸는 방식 사용하기
Event Construct
→ Branch (bIsHost)
├─ true (호스트일 때)
│ StartButton → Set Visibility: Visible
│ ReadyButton → Set Visibility: Collapsed (또는 Hidden)
└─ false (클라이언트일 때)
StartButton → Set Visibility: Collapsed
ReadyButton → Set Visibility: Visible
UI는 기본적으로 각 클라이언트 로컬에만 렌더링되기 때문에
이렇게 분기해도 서로 화면이 섞이지 않는다.
CommonUI 쓰는 경우, 구조는 똑같고 "어디에 위젯을 Push 하느냐"만 따로 생각하기
Create Widget (WBP_Lobby)Push Content나 Push Layer로 CommonActivatableWidget 띄우기bIsHost bool은 Exposed on Spawn으로 넘겨주면 동일하게 작동함"ViewPort에 직접 올리냐 / CommonUI 스택에 올리냐" 만 다름

Overlay
void ULobbyWidget::NativeConstruct()
{
Super::NativeConstruct();
// Host 여부 확인 GS에서 GI로 수정
if (ULNGameInstance* GI = GetGameInstance<ULNGameInstance>())
{
bIsHost = GI->IsLocalHost();
}
// 버튼 이벤트 바인딩
if (Btn_Back)
{
Btn_Back->OnClicked().AddUObject(this, &ULobbyWidget::OnBackClicked);
}
if (Btn_Start)
{
Btn_Start->OnClicked().AddUObject(this, &ULobbyWidget::OnStartClicked);
}
if (Btn_Ready)
{
Btn_Ready->OnClicked().AddUObject(this, &ULobbyWidget::OnReadyClicked);
}
// Host / Client - UI 분기
if (bIsHost)
{
Btn_Start->SetVisibility(ESlateVisibility::Visible);
Btn_Ready->SetVisibility(ESlateVisibility::Collapsed);
}
else
{
Btn_Start->SetVisibility(ESlateVisibility::Collapsed);
Btn_Ready->SetVisibility(ESlateVisibility::Visible);
}
// ...
}
void ULobbyWidget::OnStartClicked()
{
UE_LOG(LogTemp, Warning, TEXT("START clicked"));
if (!bIsHost)
{
return;
}
APlayerController* PC = GetOwningPlayer();
if (!PC)
{
return;
}
if (ALNControllerInGame* C = Cast<ALNControllerInGame>(PC))
{
C->Server_RequestStart();
}
}
void ULobbyWidget::OnReadyClicked()
{
UE_LOG(LogTemp, Warning, TEXT("READY clicked"));
APlayerController* PC = GetOwningPlayer();
if (!PC)
{
return;
}
if (ALNControllerInGame* C = Cast<ALNControllerInGame>(PC))
{
C->ToggleReadyState();
}
// Ready 버튼만 비활성화 (UI 유지)
// Btn_Ready->SetIsEnabled(false);
}
// 플레이어 모두 Ready -> Start 버튼 활성화
void ULobbyWidget::OnAllReadyChanged(bool bReady)
{
UE_LOG(LogTemp, Warning, TEXT("AllReady Changed: %d"), bReady ? 1 : 0);
if (bIsHost && Btn_Start)
{
Btn_Start->SetIsEnabled(bReady);
Btn_Start->SetRenderOpacity(bReady ? 1.0f : 0.4f);
}
}

접속한 플레이어 수를 보여주는 UI
CommonText로 만들기
// LobbyWidget.h
FTimerHandle PlayerCountTimerHandle;
UFUNCTION()
void UpdatePlayerCount();
// LobbyWidget.cpp
void ULobbyWidget::NativeConstruct()
{
// ...
ALNGameState* GS = GetWorld()->GetGameState<ALNGameState>();
if (GS)
{
// ...
// 0.2초마다 UI 자동 갱신
GetWorld()->GetTimerManager().SetTimer(
PlayerCountTimerHandle,
this,
&ULobbyWidget::UpdatePlayerCount,
0.2f,
true
);
}
void ULobbyWidget::UpdatePlayerCount()
{
if (!CT_PlayerCount)
{
return;
}
ALNGameState* GS = GetWorld()->GetGameState<ALNGameState>();
if (!GS)
{
return;
}
const int32 CurrentPlayers = GS->PlayerArray.Num();
const int32 MaxPlayers = GS->MaxPlayers;
CT_PlayerCount->SetText(
FText::FromString(FString::Printf(TEXT("%d / %d"), CurrentPlayers, MaxPlayers))
);
}