C++ 로 채팅 예제를 구현해보며 아래와 같은 기능을 만들어 보았다.
1. 채팅 기능
2. 서버에 유저네임 저장하여 중복 체크 & 메세지 출력 색상 지정
아래와 같은 요소들로 구현하였다.
1. 채팅 기능
- UEditableText 로 메세지 작성 & 커밋
- 텍스트 커밋 시 플레이어 컨트롤러에서 서버 (게임모드) 로 전송
- 게임모드에서 메세지 각 클라이언트 컨트롤러에 프린트하는 함수 호출
2. 유저네임 저장 / 중복 체크 / 색상 지정
- 게임모드에 TMap 으로 유저네임-색상 관리
- 로그인 위젯에서 유저네임 설정 시 TMap 에 이미 등록되어 있는지 체크 후 유저네임-랜덤색상 페어 저장
- 중복 시 안내 메세지 표시
- 클라이언트에 메세지 출력 요청 시 해당 색상 전달하여 지정된 색상으로 출력
1. 채팅 기능
1) 위젯 생성 & 함수 바인드
void AChatController::CreateChatWidget()
{
if (ChatWidgetClass && ChatWidget == nullptr && IsLocalController())
{
ChatWidget = CreateWidget<UChatWidget>(this, ChatWidgetClass, TEXT("ChatWidget"));
if (ChatWidget)
{
ChatWidget->AddToViewport();
// Bind ServerSendMessage to OnTextCommitted delegate of TextBox
ChatWidget->MessageTextBox->OnTextCommitted.AddDynamic(this, &AChatController::ServerSendMessage);
}
}
}
2) 텍스트 커밋 시 게임모드의 서버 RPC 를 호출하는 아래 함수를 바인드한다.
void AChatController::ServerSendMessage_Implementation(const FText& Text, ETextCommit::Type CommitType)
{
if (CommitType == ETextCommit::OnEnter)
{
if (AChatModeBase* ChatModeBase = Cast<AChatModeBase>(UGameplayStatics::GetGameMode(this)))
{
ChatModeBase->ServerRelayMessage(Username, Text);
}
}
}
3) 게임모드의 서버 RPC 는 서버 내 플레이어 컨트롤러에 클라이언트 RPC로 출력을 요청한다.
후술할 내용이지만, 유저네임-컬러 맵에 저장된 컬러를 클라이언트 RPC에 전달해 해당 색상으로 출력하도록 한다.
void AChatModeBase::ServerRelayMessage_Implementation(const FString& Username, const FText& Message)
{
for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; Iterator++)
{
if (AChatController* ChatController = Cast<AChatController>(*Iterator))
{
FColor Color = FColor::White;
if (FColor* ColorPtr = UserColorMap.Find(Username))
{
Color = *ColorPtr;
}
ChatController->ClientPrintMessage(FText::FromString(Username + TEXT(": ") + Message.ToString()), Color);
}
}
}
4) 컨트롤러의 클라이언트 RPC 에서 전달받은 색상으로 텍스트 출력
// Client RPC that prints the message relayed from ChatModeBase (server)
void AChatController::ClientPrintMessage_Implementation(const FText& Text, const FColor& Color)
{
if (HasAuthority())
{
GEngine->AddOnScreenDebugMessage(-1, 3.f, Color, Text.ToString());
}
}
* HasAuthority() 체크로 중복 출력 방지
5) ChatWidget 에는 텍스트 커밋 시 텍스트를 지우도록 간단히 구현
void UChatWidget::NativeConstruct()
{
MessageTextBox->OnTextCommitted.AddDynamic(this, &UChatWidget::EmptyTextBox);
}
void UChatWidget::EmptyTextBox(const FText& Text, ETextCommit::Type CommitType)
{
MessageTextBox->SetText(FText::GetEmpty());
}
2. 유저네임 서버 관리
1) 게임모드에서 TMap<FString, FColor> 로 유저네임-지정색상 관리
UPROPERTY()
TMap<FString, FColor> UserColorMap;
2) 로그인 위젯에서 유저네임 입력 후 Confirm 버튼 클릭 시 중복 아닌지 체크
// Call Server RPC to check the username when 'Confirm' button is clicked
void AChatController::UsernameConfirmed()
{
if (LoginWidget)
{
ServerCheckUsername(LoginWidget->Username);
}
}
// Check if the username already exists (in GameMode)
void AChatController::ServerCheckUsername_Implementation(const FString& InUsername)
{
if (AChatModeBase* ChatModeBase = Cast<AChatModeBase>(UGameplayStatics::GetGameMode(this)))
{
// If the username already exists, call Client RPC to display a "fail" message on the widget
if (ChatModeBase->UserColorMap.Find(InUsername) != nullptr)
{
ClientNotifyUsernameFailed();
return;
}
}
// Set server-side username
ServerSetUsername(InUsername);
}
- 게임모드의 UserColorMap 에 Username 이 이미 존재하는지 체크
3) 이미 있으면 클라이언트에 "중복" 메세지 출력
// Display "Username already taken" message on the widget
void AChatController::ClientNotifyUsernameFailed_Implementation()
{
if (LoginWidget)
{
LoginWidget->DisplayUsernameTaken();
}
}
4) 중복이 아니면
- 게임모드 TMap 에 추가
- Username 변수 업데이트
void AChatController::ServerSetUsername_Implementation(const FString& InUsername)
{
// Add username to TMap in GameMode
if (AChatModeBase* ChatModeBase = Cast<AChatModeBase>(UGameplayStatics::GetGameMode(this)))
{
ChatModeBase->ServerAddUser(InUsername);
}
// Update Username variable (replicated)
Username = InUsername;
// For the Listen Server Host Client (whose replication doesn't automatically incur OnRep function)
if (IsLocalController())
{
OnRep_UsernameUpdated();
}
}
void AChatModeBase::ServerAddUser_Implementation(const FString& Username)
{
UserColorMap.Add(Username, FColor::MakeRandomColor());
}
꿀팁. FColor::MakeRandomColor() 라는 편리한 함수가 있다!
계획 없이 진행에서 시행착오가 많았지만... 이렇게 보니 간단한 구현이었네... ㅎㅎ
'언리얼_엔진_게임개발_공부 > 언리얼 네트워크' 카테고리의 다른 글
숫자 야구 게임 - 로비 기능 (0) | 2025.03.27 |
---|---|
C++로 채팅 예제 구현하기 - PlayerController ~ LoginWidget (0) | 2025.03.19 |
데디케이티드 서버 활용 미로 게임 예제 분석 (0) | 2025.03.18 |
Run on server / Run on owning client 잘 구분하여 쓰기 (0) | 2025.03.13 |
언리얼 엔진의 네트워크 / NetMode / Replication (0) | 2025.03.12 |