작업 트러블 슈팅 과정 

문제 상황

로비에서 팀을 선택할 때, 캐릭터 팀 컬러 변경이 제대로 이루어지지 않는 문제

빠르게 팀 변경을 할 경우 반대 팀 컬러로 설정되는 오류가 발생.

원인

기존 구조

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

+ Recent posts