채팅 기능을 구현하기위해 Player Controller에 추가한 함수는 아래와 같다.
UCLASS()
class SCIFICOMBAT_API ASciFiCombatPlayerController : public APlayerController
{
. . . . . . . . . . .
public:
// Chat System Method
UFUNCTION(Server, Reliable, BlueprintCallable)
void ServerSendMessage(const FName sender, const FText & message);
UFUNCTION(Client, Reliable, BlueprintCallable)
void ClientAddMessage(const FName sender, const FText & message);
};
void ASciFiCombatPlayerController::ServerSendMessage_Implementation(const FName sender, const FText & message)
{
TArray<AActor*> ActorsToFind;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASciFiCombatPlayerController::StaticClass(), ActorsToFind);
for (AActor* find_controller : ActorsToFind)
{
// 월드에 존재하는 플레이어 컨트롤러들을 모두 찾고, 플레이어들마다
if (IsValid(find_controller))
{
// 클라이언트 RPC 함수를 호출한다.
Cast<ASciFiCombatPlayerController>(find_controller)->ClientAddMessage(sender, message);
}
}
}
void ASciFiCombatPlayerController::ClientAddMessage_Implementation(const FName sender, const FText & message)
{
// HUD의 Chat Widget 멤버에 Messeage Widget을 Add한다.
player_hud->AddMessage(sender, message);
}
메세지를 보내는 SendMessage는 Server RPC로 호출한다. 이러면 해당 함수는 서버에서 실행이 되고, SendMessage의 내부는 월드에 존재하는 모든 플레이어 컨트롤러들의 Client RPC AddMessage 함수를 호출하게 된다.
여기서 각 플레이어 컨트롤러들은 서버를 제외하면 모두 클라이언트의 소유이기 때문에,
서버 머신에서 클라이언트가 소유권을 가지고 있는 액터가 Client RPC 함수를 호출하면, 해당 클라이언트 머신에서 함수가 실행되기 때문에 접속중인 클라이언트들도 채팅 메세지를 볼 수 있다.(쓰면서도 햇갈린다...)
UUserWidget을 상속받아 UUserChatWidget과 MessageWidget를 생성한다.
UCLASS()
class SCIFICOMBAT_API UUserChatWidget : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(meta = (BindWidget), VisibleAnyWhere, BlueprintReadWrite)
class UScrollBox* messages;
UPROPERTY(meta = (BindWidget), VisibleAnyWhere, BlueprintReadWrite)
class UEditableTextBox* message_text_box;
public:
UFUNCTION(BlueprintImplementableEvent)
void AddMessage(const FName sender, const FText& message);
};
messages는 UScrollBox 타입으로 사용자가 보낸 채팅 메세지들이 이 스크롤 박스에 Add 될 것이다. message_text_box는 UEditableTextBox 타입으로 사용자는 이 에디터 박스에 보내고자하는 메세지를 입력하고 Enter 키를 눌러서 메세지를 보낼 수 있다.
BlueprintImplementableEvent로 옵션으로 설정된 AddMessage 함수는 블루프린트에서 아래와 같이 구현한다.
message_text_box에서 메세지를 입력하고 엔터키를 눌렀을 때 발생하는 이벤트는 아래와 같이 처리한다.
UserChatWidget의 멤버인 messages에 Child로써 Add될 UserChatMessage는 아래와 같이 구성한다.
UCLASS()
class SCIFICOMBAT_API UChatMessageWidget : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, Category = HUD, BlueprintReadWrite)
FName sender;
UPROPERTY(EditAnywhere, Category = HUD, BlueprintReadWrite)
FText message;
UPROPERTY(meta = (BindWidget), VisibleAnyWhere, BlueprintReadWrite)
class UTextBlock* sender_text;
UPROPERTY(meta = (BindWidget), VisibleAnyWhere, BlueprintReadWrite)
class UTextBlock* message_text;
};
온라인 게임들을 보면 채팅 시스템에도 여러가지 기능이 달려있는데, 가장 흔하게 볼 수 있는 기능으로 /help, /w user_name과 같이 도움말을 보거나 1:1 채팅을 하는 등 채팅 메세지에 옵션을 걸어 편의성을 제공할 수 있고 /춤, /도발, /웃음과 같이 특정 메세지를 입력하면 캐릭터가 춤을 추거나 도발 모션등을 취하는 오락성 기능을 추가할 수도 있을것이다.
ServerSendMessage를 조금 손보면 구현할 수 있을것같다...