KLingo Project Documentation 1.0.0
Unreal Engine 5.6 C++ Project Documentation
로딩중...
검색중...
일치하는것 없음
TutorialComponent.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 "TutorialComponent.h"
5
6#include "APedestalSwitch.h"
7#include "APlayerControl.h"
8#include "luggage.h"
9#include "UBroadcastManager.h"
10#include "GameFramework/Character.h"
11
12
13// Sets default values for this component's properties
14UTutorialComponent::UTutorialComponent()
15{
16 // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
17 // off to improve performance if you don't need them.
18 PrimaryComponentTick.bCanEverTick = true;
19
20 // ...
21
22 CurrentStep = ETutorialStep::Waiting;
23 OwnerController = nullptr;
24}
25
26
27// Called when the game starts
28void UTutorialComponent::BeginPlay()
29{
30 Super::BeginPlay();
31
32 // ...
33 OwnerController = Cast<APlayerController>(GetOwner());
34 if (!OwnerController)
35 {
36 UE_LOG(LogTemp, Error, TEXT("TutorialComponent: Owner is not a PlayerController!"));
37 return;
38 }
39
40 LastControlRotation = OwnerController->GetControlRotation();
41}
42
43
44// Called every frame
45void UTutorialComponent::TickComponent(float DeltaTime, ELevelTick TickType,
46 FActorComponentTickFunction* ThisTickFunction)
47{
48 Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
49
50 if (OwnerController)
51 {
52 FRotator CurrentRotation = OwnerController->GetControlRotation();
53
54 // 튜토리얼 중이면 입력 조건 체크
55 if (CurrentStep != ETutorialStep::Completed && CurrentStep != ETutorialStep::Waiting)
56 {
57 CheckInputConditions();
58 }
59
60 LastControlRotation = CurrentRotation;
61 }
62}
63
64void UTutorialComponent::StartTutorial()
65{
66 SetStep(ETutorialStep::MouseLook);
67}
68
69void UTutorialComponent::AdvanceToNextStep()
70{
71 UE_LOG(LogTemp, Warning, TEXT("[AdvanceToNextStep] Called! CurrentStep: %d"), (int32)CurrentStep);
72
73 // 현재 메시지 숨김
74 if (UBroadcastManager* BM = UBroadcastManager::Get(GetWorld()))
75 {
76 BM->SendHideTutorialMessage();
77 }
78
79 ETutorialStep NextStep = GetNextStep(CurrentStep);
80 UE_LOG(LogTemp, Warning, TEXT("[AdvanceToNextStep] NextStep: %d"), (int32)NextStep);
81 SetStep(NextStep);
82}
83
84void UTutorialComponent::SetStep(ETutorialStep NewStep)
85{
86 CurrentStep = NewStep;
87 bInputConditionMet = false; // 플래그 초기화
88
89 // 상호작용 플래그 초기화
90 bGrabbedLuggage = false;
91 bPickedUpSomething = false;
92 bInteractedWithSwitch = false;
93
94 if (UBroadcastManager* BM = UBroadcastManager::Get(GetWorld()))
95 {
96 BM->SendTutorialStepChanged(OwnerController, NewStep);
97
98 FText TutorialMessage = GetTutorialMessage(NewStep);
99 if (NewStep == ETutorialStep::Completed)
100 {
101 BM->SendTutorMessage(TutorialMessage);
102
103 // 튜토리얼 완료 시 PlayerControl에 알림
104 if (APlayerControl* PC = Cast<APlayerControl>(OwnerController))
105 {
106 PC->OnTutorialCompleted();
107 }
108 }
109 else
110 {
111 BM->SendShowTutorialMessage(TutorialMessage);
112 }
113 }
114
115 UE_LOG(LogTemp, Log, TEXT("Tutorial Step Changed: %d"), (int32)NewStep);
116}
117
118bool UTutorialComponent::IsTutorialCompleted() const
119{
120 return CurrentStep == ETutorialStep::Completed;
121}
122
123void UTutorialComponent::CheckInputConditions()
124{
125 if (!OwnerController || bInputConditionMet) return;
126
127 bool bConditionMet = false;
128
129 switch (CurrentStep)
130 {
131 case ETutorialStep::MouseLook:
132 bConditionMet = CheckMouseLookInput();
133 break;
134 case ETutorialStep::Movement:
135 bConditionMet = CheckMovementInput();
136 break;
137 case ETutorialStep::Sprint:
138 bConditionMet = CheckSprintInput();
139 break;
140 case ETutorialStep::Jump:
141 bConditionMet = CheckJumpInput();
142 break;
143 case ETutorialStep::PickUp:
144 bConditionMet = CheckPickUpInput();
145 break;
146 case ETutorialStep::GrabGun:
147 bConditionMet = CheckGrabGunInput();
148 break;
149 case ETutorialStep::Interaction:
150 bConditionMet = CheckInteractionInput();
151 break;
152 default:
153 break;
154 }
155
156 if (bConditionMet && !bInputConditionMet)
157 {
158 UE_LOG(LogTemp, Warning, TEXT("[CheckInputConditions] Condition met! Advancing to next step..."));
159 bInputConditionMet = true;
160 OnInputConditionMet();
161 }
162}
163
164void UTutorialComponent::OnInputConditionMet()
165{
166 if (AdvanceDelayTimerHandle.IsValid())
167 {
168 GetWorld()->GetTimerManager().ClearTimer(AdvanceDelayTimerHandle);
169 }
170
171 GetWorld()->GetTimerManager().SetTimer(AdvanceDelayTimerHandle, this,
172 &UTutorialComponent::AdvanceToNextStep, 1.5f, false);
173}
174
175ETutorialStep UTutorialComponent::GetNextStep(ETutorialStep Step) const
176{
177 switch (Step)
178 {
179 case ETutorialStep::Waiting: return ETutorialStep::MouseLook;
180 case ETutorialStep::MouseLook: return ETutorialStep::Movement;
181 case ETutorialStep::Movement: return ETutorialStep::Sprint;
182 case ETutorialStep::Sprint: return ETutorialStep::Jump;
183 case ETutorialStep::Jump: return ETutorialStep::GrabGun;
184 case ETutorialStep::GrabGun: return ETutorialStep::PickUp;
185 case ETutorialStep::PickUp: return ETutorialStep::Interaction;
186 case ETutorialStep::Interaction: return ETutorialStep::Completed;
187 default: return ETutorialStep::Completed;
188 }
189}
190
191bool UTutorialComponent::CheckMouseLookInput() const
192{
193 if (!OwnerController) return false;
194
195 FRotator CurrentRotation = OwnerController->GetControlRotation();
196 FRotator DeltaRotation = CurrentRotation - LastControlRotation;
197
198 // 회전 변화가 임계값 이상인지 확인 (Pitch = 상하, Yaw = 좌우)
199 return FMath::Abs(DeltaRotation.Pitch) > 0.5f || FMath::Abs(DeltaRotation.Yaw) > 0.5f;
200}
201
202bool UTutorialComponent::CheckMovementInput() const
203{
204 if (!OwnerController) return false;
205
206 APawn* Pawn = OwnerController->GetPawn();
207 if (!Pawn) return false;
208
209 // WASD
210 FVector InputVector = Pawn->GetLastMovementInputVector();
211 return !InputVector.IsNearlyZero();
212}
213
214bool UTutorialComponent::CheckSprintInput() const
215{
216 if (!OwnerController) return false;
217
218 // Shift
219 return OwnerController->IsInputKeyDown(EKeys::LeftShift);
220}
221
222bool UTutorialComponent::CheckJumpInput() const
223{
224 if (!OwnerController) return false;
225
226 return OwnerController->IsInputKeyDown(EKeys::SpaceBar);
227}
228
229bool UTutorialComponent::CheckPickUpInput() const
230{
231 //UE_LOG(LogTemp, Warning, TEXT("[CheckPickUpInput] bPickedUpSomething: %d"), bPickedUpSomething);
232 return bPickedUpSomething;
233}
234
235bool UTutorialComponent::CheckGrabGunInput() const
236{
237 // 오른쪽 마우스 버튼 클릭
238 //return OwnerController->WasInputKeyJustPressed(EKeys::RightMouseButton);
239 return bGrabbedLuggage;
240}
241
242bool UTutorialComponent::CheckInteractionInput() const
243{
244 // E키
245 //return OwnerController->WasInputKeyJustPressed(EKeys::E);
246 return bInteractedWithSwitch;
247}
248
249FText UTutorialComponent::GetTutorialMessage(ETutorialStep Step) const
250{
251 switch (Step)
252 {
253 case ETutorialStep::MouseLook:
254 return FText::FromString(TEXT("Move mouse to look around"));
255 case ETutorialStep::Movement:
256 return FText::FromString(TEXT("Press W/A/S/D to walk"));
257 case ETutorialStep::Sprint:
258 return FText::FromString(TEXT("Press Shift to sprint"));
259 case ETutorialStep::Jump:
260 return FText::FromString(TEXT("Press Spacebar to jump"));
261 case ETutorialStep::PickUp:
262 return FText::FromString(TEXT("Left Click to pick up"));
263 case ETutorialStep::GrabGun:
264 return FText::FromString(TEXT("Right Click to grab things from far away"));
265 case ETutorialStep::Interaction:
266 return FText::FromString(TEXT("Press E to activate switch"));
267 case ETutorialStep::Completed:
268 return FText::FromString(TEXT("Tutorial finished!"));
269 default:
270 return FText::GetEmpty();
271 }
272}
273
274void UTutorialComponent::OnObjectGrabbed(AActor* GrabbedObject)
275{
276 if (CurrentStep != ETutorialStep::GrabGun) return;
277
278 if (GrabbedObject && GrabbedObject->IsA(Aluggage::StaticClass()))
279 {
280 bGrabbedLuggage = true;
281 }
282}
283
284void UTutorialComponent::OnObjectPickedUp(AActor* PickedObject)
285{
286 if (CurrentStep != ETutorialStep::PickUp) return;
287
288 if (PickedObject && PickedObject->IsA(Aluggage::StaticClass()))
289 {
290 bPickedUpSomething = true;
291 }
292}
293
294void UTutorialComponent::OnObjectInteracted(AActor* InteractedObject)
295{
296 if (CurrentStep != ETutorialStep::Interaction) return;
297
298 if (InteractedObject && InteractedObject->IsA(APedestalSwitch::StaticClass()))
299 {
300 bInteractedWithSwitch = true;
301 }
302}
303
APlayerControl 선언에 대한 Doxygen 주석을 제공합니다.
ETutorialStep
튜토리얼 진행 단계
게임 내 전역 이벤트를 중계하는 중앙 이벤트 버스(Event Bus) 서브시스템입니다.