
기탁님이 만들어두신 위젯 블루프린트에 이미지 추가하기 (HoverImage는 다른 걸로)
근데 채팅로그가 흰색이고 얼음 배경이라 안 보여서 보더로 감싸기

보더(0.1,0.1,0.1,0.5) - 반투명한 회색 배경 만들기
채팅 입력할 때 무음이면 심심하니까 키보드 사운드 추가하기~
WaitingLevel은 위젯 블루프린트가 여러 개라 배경음악은 레벨 블루프린트에 연결하기

원하는 것:
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "ChatWidget.generated.h"
class UScrollBox;
class UEditableTextBox;
/**
* 채팅 위젯 (닉네임 + 메시지 + 폰트 + 색상)
*/
UCLASS()
class DC_API UChatWidget : public UUserWidget
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
// 한 줄 추가
UFUNCTION(BlueprintCallable)
void AddChatMessage(const FString& Sender, const FString& Text);
// 히스토리 재구성
UFUNCTION(BlueprintCallable)
void RebuildFromHistory(const TArray<FString>& Messages);
private:
// WBP_Chat에 만든 ScrollBox 이름 → 반드시 같아야 함
UPROPERTY(meta=(BindWidget))
UScrollBox* ChatLog;
// WBP_Chat에 만든 EditableTextBox 이름 → 반드시 같아야 함
UPROPERTY(meta=(BindWidget))
UEditableTextBox* InputBox;
// 입력창 Enter 처리
UFUNCTION()
void OnInputCommitted(const FText& Text, ETextCommit::Type CommitMethod);
// 김여울
// 닉네임에 고유 색상 할당하기
FLinearColor GetColorForNickname(const FString& Nickname);
// 김여울
// 이미 배정된 닉네임 (색상 저장용)
TMap<FString, FLinearColor> NicknameColorMap;
// 김여울
// 랜덤 컬러 할당하기
FLinearColor GenerateRandomColor();
#pragma region Chat Font
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Chat")
UFont* ChatFont;
#pragma endregion Chat Font
};
#include "UI/ChatWidget.h"
#include "Components/ScrollBox.h"
#include "Components/EditableTextBox.h"
#include "Components/TextBlock.h"
#include "../Server/Waiting/WaitingPlayerController.h"
#include "Components/HorizontalBox.h"
#include "Components/HorizontalBoxSlot.h"
#include "UObject/ConstructorHelpers.h"
#include "Engine/Font.h"
void UChatWidget::NativeConstruct()
{
Super::NativeConstruct();
if (InputBox)
{
// Enter 입력 시 OnInputCommitted 호출
InputBox->OnTextCommitted.AddDynamic(this, &UChatWidget::OnInputCommitted);
}
}
void UChatWidget::OnInputCommitted(const FText& Text, ETextCommit::Type CommitMethod)
{
if (CommitMethod != ETextCommit::OnEnter) return;
FString Clean = Text.ToString().TrimStartAndEnd();
if (Clean.IsEmpty())
{
if (InputBox) InputBox->SetText(FText::GetEmpty());
return;
}
// 일단은 로컬에만 출력 (다음 단계에서 PlayerController와 서버 RPC 연결)
//AddChatMessage(TEXT("Me"), Clean);
// ===== 서버 RPC로 전송 =====
if (APlayerController* PC = GetOwningPlayer())
{
if (AWaitingPlayerController* MyPC = Cast<AWaitingPlayerController>(PC))
{
MyPC->ServerSendChatMessage(Clean);
}
}
if (InputBox) InputBox->SetText(FText::GetEmpty());
}
// 김여울
// 닉네임 고유 색상 리턴 (기존에 없으면 새로 생성해서 캐싱)
FLinearColor UChatWidget::GetColorForNickname(const FString& Nickname)
{
if (NicknameColorMap.Contains(Nickname))
{
return NicknameColorMap[Nickname];
}
FLinearColor NewColor = GenerateRandomColor();
NicknameColorMap.Add(Nickname, NewColor);
return NewColor;
}
// 김여울
// 컬러 생성 (HSL 기반으로 명도 조절)
FLinearColor UChatWidget::GenerateRandomColor()
{
float Hue = FMath::FRandRange(0.f, 360.f);
float Saturation = FMath::FRandRange(0.6f, 1.0f); // 조금 더 진하게
float Value = FMath::FRandRange(0.7f, 1.0f); // 밝기 유지
FLinearColor HSV(Hue, Saturation, Value);
return HSV.HSVToLinearRGB();
}
// 김여울 (코드 수정)
void UChatWidget::AddChatMessage(const FString& Sender, const FString& Text)
{
if (!ChatLog) return;
// 입력창(Font) 기준으로 폰트 설정
FSlateFontInfo AppliedFont;
if (ChatFont)
{
AppliedFont = FSlateFontInfo(ChatFont, 20); // 블루프린트에서 지정한 폰트 사용
}
else if (InputBox)
{
AppliedFont = InputBox->WidgetStyle.TextStyle.Font; // 입력창 폰트 사용
}
else
{
AppliedFont.Size = 20; // 기본 폰트
}
// 수평 박스 만들기 (닉네임 + 메세지 나란히)
// 메시지를 수평 정렬하기 위한 박스 생성
UHorizontalBox* MessageRow = NewObject<UHorizontalBox>(this, UHorizontalBox::StaticClass());
if (!MessageRow) return;
// 닉네임 블럭
UTextBlock* NicknameBlock = NewObject<UTextBlock>(this, UTextBlock::StaticClass());
if (NicknameBlock)
{
NicknameBlock->SetText(FText::FromString(Sender + TEXT(": ")));
NicknameBlock->SetFont(AppliedFont);
NicknameBlock->SetColorAndOpacity(FSlateColor(GetColorForNickname(Sender)));
MessageRow->AddChildToHorizontalBox(NicknameBlock);
}
// 메시지 블럭
UTextBlock* MessageBlock = NewObject<UTextBlock>(this, UTextBlock::StaticClass());
if (MessageBlock)
{
MessageBlock->SetText(FText::FromString(Text));
MessageBlock->SetFont(AppliedFont);
MessageBlock->SetColorAndOpacity(FSlateColor(FLinearColor::White));
// 줄바꿈 설정
MessageBlock->SetAutoWrapText(true);
MessageBlock->SetWrapTextAt(600.0f);
MessageRow->AddChildToHorizontalBox(MessageBlock);
}
// ScrollBox에 추가 및 스크롤 최하단 이동
ChatLog->AddChild(MessageRow);
ChatLog->ScrollToEnd();
}
void UChatWidget::RebuildFromHistory(const TArray<FString>& Messages)
{
if (!ChatLog) return;
ChatLog->ClearChildren();
for (const FString& Msg : Messages)
{
UTextBlock* NewLine = NewObject<UTextBlock>(this);
NewLine->SetText(FText::FromString(Msg));
ChatLog->AddChild(NewLine);
}
ChatLog->ScrollToEnd();
}

완성~