이전에 BluePrint로 만들었던 ScrollChat을 C++로 구현을 해보았다. 나아가 실제 게임에서 RPC와 Replecated 가 어떻게 작동하는지 학습하기 위해 ChatBased-Baseball 게임을 만들어보았다.
Project : Baseball MultiGame Project
Duration : 2025.03.10 ~ 2025.03.28
GitHub : https://github.com/JungHyaechang/TBaseballMultiGame
YouTube : https://www.youtube.com/watch?v=Jttnoeh8Wf8
앞서 만들었던 BluePrint를 기반으로 로직을 설계하여 UML을 작성.
BluePrint으로 작성한 ScrollChat : https://velog.io/@hch9097/ScrollChat-BP-Implement
PostLogin
은 Unreal에서 서버에서 플레이어가 정상적으로 접속을 완료한 후 처리할 로직을 넣는 데 사용.
void ABBGameMode::PostLogin(APlayerController* NewPlayer)
{
Super::PostLogin(NewPlayer);
if (APlayerState* PS = NewPlayer->PlayerState)
{
FString Name = FString::Printf(TEXT("Player%d"), PlayerIndex++);
PS->SetPlayerName(Name);
}
}
GameMode의 InitNewPlayer()
에서 접속한 Client에 PlayerController와 PlayerState가 할당 됨. 따라서 안전하게 PlayerState를 가져올 수 있었음.
PlayerIndex는 GameMode에서 선언된 변수로 GameMode생성자에서 PlayerIndex = 1 로 초기화됨.
따라서 접속한 Player마다 1,2,3...순서로 Player1, Player2, Player3 ... 이런식으로 이름이 부여되고 PlayerName의 SetPlayerName을 통해 이름을 변경.
PlayerName
과 GetPlayerName()
, SetPlayerName()
은 Unreal Engine 에서 기본으로 제공하는 APlayerState클래스에 내장된 기능. Replecated 되어 있어서 서버->클라이언트로 자동 동기화 된다.
void ABBGameMode::BraodcastMessage(const FString& Message)
{
for (APlayerState* PS = GameState->PlayerArray)
{
if (APlayerController* PC = Cast<APlayerController>(PlayerState->GetOwner()))
{
if (UChatComponent* Chat = PC->FindComponentByClass<UChatComponent>())
{
Chat->AddSystemChatMessageOnOwningClient(Message);
}
}
}
}
// AGameModeBase.h (언리얼 내부 코드 일부)
UPROPERTY(Transient)
AGameModeBase* GameState
GameMode가 시작될 때 엔진이 자동으로 생성한 GameState 인스턴스를 여기에 할당함.
GameState->
로 쓰는것이 가능. 선언 안해도 됌.PlayerArray는 Unreal Engine이 기본으로 제공하는 시스템용 배열이다.
Replicated
변수이기 때문에 클라이언트에도 자동 전파// AGameStateBase.h (언리얼 내부 코드 일부)
UPROPERTY(Transient)
TArray<TObjectPtr<APlayerState>> PlayerArray;
FindComponentByClass를 이용하여 PlayerController에 있는 ChatComponent에 접근
_Implementation()
이 클라이언트에서 실행되도록 해줌.따라서 NetMulticast 에 대한 함수를 GameMode에 만들어 본다면
void ABBGameMode::BraodcastMessage(APlayerController* Sender, const FString& Message)
{
if (UChatComponent* Chat = PC->FindComponentByClass<UChatComponent>())
{
Chat->MulticastAddSystemChatMessageOnOwningClient(Message);
}
}
이렇게 하는게 훨씬 효과적임.
Actor를 보고있는 Client가 아닌 특정 Client에 뭔가를 보낼때 씀
확장성과 수정이 용이하게 설계를 하기 위해여 PlayerController 하위로 ActorComponent를 이용하여 플레이어의 입력, UI 관리