KLingo Project Documentation 1.0.0
Unreal Engine 5.6 C++ Project Documentation
로딩중...
검색중...
일치하는것 없음
ChatWidget.cpp
이 파일의 문서화 페이지로 가기
1// Copyright (c) 2025 Doppleddiggong. All rights reserved. Unauthorized copying, modification, or distribution of this file, via any medium is strictly prohibited. Proprietary and confidential.
2
3
4#include "ChatWidget.h"
5
6#include "APlayerControl.h"
7#include "ChatBoxWidget.h"
8#include "ChatInputBox.h"
9#include "GameLogging.h"
10#include "Blueprint/WidgetBlueprintLibrary.h"
11#include "Components/MultiLineEditableTextBox.h"
12#include "Components/ScrollBox.h"
13#include "Components/ScrollBoxSlot.h"
14#include "Components/VerticalBox.h"
15#include "GameFramework/GameStateBase.h"
16
17UChatWidget::UChatWidget(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
18{
19 ConstructorHelpers::FClassFinder<UChatBoxWidget> LeftChatBoxWidgetClassRef(TEXT("/Game/CustomContents/UI/Widgets/Chat/WBP_LeftChatMessage.WBP_LeftChatMessage_C"));
20 if (LeftChatBoxWidgetClassRef.Succeeded())
21 {
22 LeftChatBoxWidgetClass = LeftChatBoxWidgetClassRef.Class;
23 }
24 ConstructorHelpers::FClassFinder<UChatBoxWidget> RightChatBoxWidgetClassRef(TEXT("/Game/CustomContents/UI/Widgets/Chat/WBP_RightChatMessage.WBP_RightChatMessage_C"));
25 if (RightChatBoxWidgetClassRef.Succeeded())
26 {
27 RightChatBoxWidgetClass = RightChatBoxWidgetClassRef.Class;
28 }
29}
30
32{
33 Super::NativeConstruct();
34
35 SetIsFocusable(true);
36
37 // 초기 상태는 페이드아웃 (약간 투명하게)
38 SetRenderOpacity(0.2f);
39 CurrentOpacity = 0.2f;
40 TargetOpacity = 0.2f;
41
42 // ChatInputBox에 자신을 설정
43 if (ChatInputBox)
44 {
45 ChatInputBox->SetOwningChatWidget(this);
46 }
47}
48
49void UChatWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
50{
51 Super::NativeTick(MyGeometry, InDeltaTime);
52
53 // 페이드 처리
55 {
56 // 부드럽게 Opacity 변경
57 float Delta = FadeSpeed * InDeltaTime;
59 {
60 CurrentOpacity = FMath::Max(CurrentOpacity - Delta, TargetOpacity);
61 }
62 else
63 {
64 CurrentOpacity = FMath::Min(CurrentOpacity + Delta, TargetOpacity);
65 }
66
67 SetRenderOpacity(CurrentOpacity);
68
69 // 목표 도달 시 페이드 종료
70 if (FMath::IsNearlyEqual(CurrentOpacity, TargetOpacity, 0.01f))
71 {
72 bIsFading = false;
73 }
74 }
75}
76
77void UChatWidget::SendMessage(FResponseUserMe sendUser, FText inMessage, int32 PlayerIndex)
78{
79 auto* PC = Cast<APlayerControl>(GetWorld()->GetFirstPlayerController<APlayerController>());
80 if (!PC)
81 {
82 PRINTLOG(TEXT("Cannot get playercontroller"));
83 }
84
85 // 메시지 받은 플레이어 정보 가져오기
86 FResponseUserMe info = PC->GetUserInfo();
87 bool bIsSender = (info.id == sendUser.id);
88
89 // ChatBox 생성
90 UChatBoxWidget* newChat = CreateChatBox(bIsSender);
91 newChat->SetMessage(inMessage);
92
93 newChat->SetPlayerProfile(
94 sendUser.GetChatProfileBg(PlayerIndex),
95 sendUser.GetChatProfileTextureType(PlayerIndex));
96
97 newChat->SetPlayerName(FText::FromString(sendUser.username));
98 newChat->SetMessage(inMessage);
99 newChat->SetChatBubbleColor(bIsSender);
100
101 // ChatBox에 추가 & 정렬
102 VerticalBox_Content->AddChild(newChat);
103
104 UScrollBoxSlot* parentSlot = Cast<UScrollBoxSlot>(newChat->Slot);
105 if (parentSlot)
106 {
107 parentSlot->SetHorizontalAlignment((bIsSender ? HAlign_Left : HAlign_Right));
108 }
109
110 // 위젯의 레이아웃을 강제로 갱신하여 정확한 크기 계산
111 newChat->ForceLayoutPrepass();
112
113 // 부모 위젯들의 레이아웃을 무효화하여 다음 틱에 재계산
114 VerticalBox_Content->InvalidateLayoutAndVolatility();
115 ScrollBox_ChatBox->InvalidateLayoutAndVolatility();
116
117 // 현재 스크롤 값 & 마지막 스크롤 값
118 float scrollOffset = ScrollBox_ChatBox->GetScrollOffset();
119 float scrollOffsetOfEnd = ScrollBox_ChatBox->GetScrollOffsetOfEnd();
120
121 if (bIsSender || scrollOffset == scrollOffsetOfEnd)
122 {
123 // 레이아웃 갱신 후 스크롤 (타이머 사용)
124 FTimerHandle ScrollTimerHandle;
125 GetWorld()->GetTimerManager().SetTimer(ScrollTimerHandle, [this, newChat]()
126 {
127 // 마지막 위젯을 뷰에 표시
128 ScrollBox_ChatBox->ScrollWidgetIntoView(newChat, true, EDescendantScrollDestination::BottomOrRight);
129
130 // 추가로 ScrollToEnd도 실행
131 ScrollBox_ChatBox->ScrollToEnd();
132 }, 0.1f, false);
133 }
134
135 UWidgetBlueprintLibrary::SetFocusToGameViewport();
136 PC->SetInputMode(FInputModeGameOnly());
137 PC->SetShowMouseCursor(false);
138
139 // 채팅창을 완전히 보이게 하고 5초 후 페이드아웃 타이머 시작
140 TargetOpacity = 1.0f;
141 CurrentOpacity = 1.0f;
142 SetRenderOpacity(1.0f);
143 bIsFading = false;
144
146}
147
149{
150 ChatInputBox->SetInputFocus(true);
151
152 // 입력 포커스를 얻을 때 완전히 보이게 하고 타이머 중단
153 TargetOpacity = 1.0f;
154 CurrentOpacity = 1.0f;
155 SetRenderOpacity(1.0f);
156 bIsFading = false;
157
158 // 타이머 중단
159 if (GetWorld() && GetWorld()->GetTimerManager().IsTimerActive(FadeOutTimerHandle))
160 {
161 GetWorld()->GetTimerManager().ClearTimer(FadeOutTimerHandle);
162 }
163}
164
166{
167 if (bHasFocus)
168 {
169 // 포커스를 얻으면 완전히 보이게 하고 타이머 중단
170 TargetOpacity = 1.0f;
171 CurrentOpacity = 1.0f;
172 SetRenderOpacity(1.0f);
173 bIsFading = false;
174
175 if (GetWorld() && GetWorld()->GetTimerManager().IsTimerActive(FadeOutTimerHandle))
176 {
177 GetWorld()->GetTimerManager().ClearTimer(FadeOutTimerHandle);
178 }
179 }
180 else
181 {
182 // 포커스를 잃으면 5초 후 페이드아웃 시작
184 }
185}
186
188{
189 if (!GetWorld())
190 return;
191
192 // 기존 타이머가 있으면 취소
193 if (GetWorld()->GetTimerManager().IsTimerActive(FadeOutTimerHandle))
194 {
195 GetWorld()->GetTimerManager().ClearTimer(FadeOutTimerHandle);
196 }
197
198 // 5초 후 페이드아웃 시작
199 GetWorld()->GetTimerManager().SetTimer(FadeOutTimerHandle, this, &UChatWidget::OnFadeOutTimerComplete, AutoHideDelay, false);
200}
201
203{
204 // 입력창에 포커스가 있으면 페이드아웃하지 않음
205 if (ChatInputBox && ChatInputBox->HasKeyboardFocus())
206 return;
207
208 // 페이드아웃 시작
209 TargetOpacity = 0.2f; // 완전히 투명하게 하지 않고 약간 보이게
210 bIsFading = true;
211}
212
214{
215 return CreateWidget<UChatBoxWidget>(GetWorld(), bIsSender? LeftChatBoxWidgetClass : RightChatBoxWidgetClass );
216}
217
APlayerControl 선언에 대한 Doxygen 주석을 제공합니다.
YiSan 전반에서 사용하는 공용 인터페이스를 선언합니다.
#define PRINTLOG(fmt,...)
Definition GameLogging.h:30
void SetMessage(FText InMessage)
void SetPlayerName(FText InPlayerName)
void SetPlayerProfile(FLinearColor InBgColor, EResourceTextureType InProfileType)
void SetChatBubbleColor(bool IsMine) const
void StartFadeOutTimer()
void SendMessage(FResponseUserMe sendUser, FText inMessage, int32 PlayerIndex)
virtual void NativeConstruct() override
TSubclassOf< class UChatBoxWidget > RightChatBoxWidgetClass
Definition ChatWidget.h:49
void OnFadeOutTimerComplete()
TObjectPtr< class UChatInputBox > ChatInputBox
Definition ChatWidget.h:42
TSubclassOf< class UChatBoxWidget > LeftChatBoxWidgetClass
Definition ChatWidget.h:46
void FocusInput()
virtual void NativeTick(const FGeometry &MyGeometry, float InDeltaTime) override
float FadeSpeed
Definition ChatWidget.h:65
UChatWidget(const FObjectInitializer &ObjectInitializer)
void OnInputFocusChanged(bool bHasFocus)
class UChatBoxWidget * CreateChatBox(bool bIsSender)
float CurrentOpacity
Definition ChatWidget.h:61
FTimerHandle FadeOutTimerHandle
Definition ChatWidget.h:57
TObjectPtr< class UScrollBox > ScrollBox_ChatBox
Definition ChatWidget.h:36
float TargetOpacity
Definition ChatWidget.h:62
TObjectPtr< class UVerticalBox > VerticalBox_Content
Definition ChatWidget.h:30
bool bIsFading
Definition ChatWidget.h:60
float AutoHideDelay
Definition ChatWidget.h:68
FLinearColor GetChatProfileBg(int player_index) const
EResourceTextureType GetChatProfileTextureType(int player_index) const