작업 트러블 슈팅 과정
문제 상황
로비에서 팀을 선택할 때, 캐릭터 팀 컬러 변경이 제대로 이루어지지 않는 문제
빠르게 팀 변경을 할 경우 반대 팀 컬러로 설정되는 오류가 발생.
원인
기존 구조
SGLobbyWidget에서 슬롯을 선택 (BlueTeam, RedTeam, Waiting)
→ HandleSlotClicked() 함수 실행
void USGLobbyWidget::HandleSlotClicked(FGameplayTag RequestedTeamTag)
{
if (!RequestedTeamTag.IsValid())
{
return;
}
ASGLobbyPlayerController* LobbyPlayerController =
GetOwningPlayer<ASGLobbyPlayerController>();
if (!IsValid(LobbyPlayerController))
{
return;
}
RefreshCharacterSelection();
}
LobbyPlayerController를 통해 팀 변경.
→ LobbyPlayerController-LobbyPlayerState를 통해 변경된 팀 태그를 받아와서 이미지에 적용.
void USGLobbyWidget::RefreshCharacterSelection()
{
APlayerController* LobbyPC = GetOwningPlayer();
ASGLobbyPlayerState* LobbyPS = LobbyPC ? Cast<ASGLobbyPlayerState>(LobbyPC->PlayerState) : nullptr;
if (!LobbyPS) return;
bool bIsWaiting = LobbyPS->GetTeamTag().GetTagName().ToString().Contains(TEXT("Waiting"));
// (...중략)
if (!bIsWaiting)
{
TArray<USGCharacterDataAsset*> FilteredList = GetFilteredCharacterList();
if (FilteredList.Num() > 0)
{
if (CurrentIndex >= FilteredList.Num())
{
CurrentIndex = 0;
}
if (Image_Character && FilteredList.IsValidIndex(CurrentIndex))
{
Image_Character->SetBrushFromTexture(FilteredList[CurrentIndex]->Thumbnail);
}
}
}
}
PlayerState에서 팀이 변경되고 LobbyWidget에서 받아올 때까지 시간이 오래 걸려 딜레이가 발생하고 이미지가 꼬이게 되었다.
해결 방법
OnRep 델리게이트 활용.
PlayerState에서 OnTeamChanged 델리게이트 생성.
기존에 팀 변경 브로드캐스트에 사용한 OnRep_ChangeTeam()에 팀 변경 브로드캐스트 로직을 추가함.
void ASGLobbyPlayerState::OnRep_ChangeTeam()
{
UE_LOG(LogTemp, Log, TEXT("%s 플레이어의 팀 태그 변경 완료: %s"), *GetPlayerName(), *CurrentTeamTag.ToString());
if (OnTeamChanged.IsBound())
{
OnTeamChanged.Broadcast();
}
if (!HasAuthority())
{
return;
}
// 팀이 바뀌었을 때도 마찬가지로 전체 명단 갱신을 요청합니다.
if (ASGLobbyGameState* GS = GetWorld()->GetGameState<ASGLobbyGameState>())
{
GS->BroadcastLobbyInfo();
}
}
→LobbyWidget에서 델리게이트 바인딩
LobbyWidget에서 PlayerState를 가져와서 RefreshCharacterSelection함수를 바인딩하는 BindPlayerState() 함수 정의
void USGLobbyWidget::BindLobbyPlayerState()
{
APlayerController* LobbyPC = GetOwningPlayer();
if (!IsValid(LobbyPC)) return;
ASGLobbyPlayerState* LobbyPS = Cast<ASGLobbyPlayerState>(LobbyPC->PlayerState);
if (!IsValid(LobbyPS)) return;
LobbyPS->OnTeamChanged.AddUniqueDynamic(this, &USGLobbyWidget::RefreshCharacterSelection);
RefreshCharacterSelection();
}
→ (핵심) 해당 함수를 LobbyPlayerController의 OnRep_PlayerState에서 호출.
PlayerState의 데이터가 변경되면 LobbyWidget에서 바인딩하는 방식이므로 PlayerState가 느리게 로딩되는 오류가 없어짐.
void ASGLobbyPlayerController::OnRep_PlayerState()
{
Super::OnRep_PlayerState();
ASGLobbyPlayerState* LobbyPS = GetPlayerState<ASGLobbyPlayerState>();
if (IsLocalController() && IsValid(LobbyPS))
{
if (USGLobbyWidget* LobbyWidget = Cast<USGLobbyWidget>(LobbyWidgetInstance))
{
LobbyWidget->BindLobbyPlayerState();
}
}
}
→ PlayerState의 팀을 변경하는 SetTeamInternal() 함수에서 ForceNetUpdate() 실행
팀 변경시 바로바로 클라이언트에게 갱신하도록 전달함으로써 서버와 클라이언트간의 딜레이 줄이기
void ASGLobbyPlayerState::SetTeamInternal(const FGameplayTag& SelectTeamTag)
{
if (HasAuthority())
{
CurrentTeamTag = SelectTeamTag;
OnRep_ChangeTeam();
ForceNetUpdate();
}
}
배운 점
- PlayerState의 정보를 가져올 때, PlayerState의 정보가 갱신되고 UI에게 전달되는 타이밍을 생각해서 연동 로직을 작성하는 방법을 배웠다.
- PlayerState처럼 PlayerController를 통해 가져오는경우 상위의 PlayerController가 준비된 후 PlayerState를 불러오는 식으로 구현하면 된다.
- On_Rep을 사용해서 레플리케이션 시 브로드캐스트 하는 방식으로 정보를 전달받는 법을 확실히 복습했다.
'Unreal5 공부 > TIL' 카테고리의 다른 글
| 2026/07/29 TIL (0) | 2026.07.29 |
|---|---|
| 2026/07/21 TIL (0) | 2026.07.21 |
| 20206/07/13 TIL (0) | 2026.07.14 |
| 2026/07/09 TIL (1) | 2026.07.09 |
| 2026/07/06 TIL (0) | 2026.07.06 |
