Chat System

김민오·2022년 9월 18일
0

Player Controller

채팅 기능을 구현하기위해 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 함수를 호출하면, 해당 클라이언트 머신에서 함수가 실행되기 때문에 접속중인 클라이언트들도 채팅 메세지를 볼 수 있다.(쓰면서도 햇갈린다...)

User Widget

UUserWidget을 상속받아 UUserChatWidget과 MessageWidget를 생성한다.

UserChatWidget

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 함수는 블루프린트에서 아래와 같이 구현한다.

Blueprints

message_text_box에서 메세지를 입력하고 엔터키를 눌렀을 때 발생하는 이벤트는 아래와 같이 처리한다.

MessageWidget

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를 조금 손보면 구현할 수 있을것같다...

profile
https://github.com/gimhema, https://gimhema.tistory.com/

0개의 댓글