forked from orfeasel/UE4-Cpp-Tutorials
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDialogSystemCharacter.cpp
More file actions
236 lines (187 loc) · 7.84 KB
/
DialogSystemCharacter.cpp
File metadata and controls
236 lines (187 loc) · 7.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "DialogSystem.h"
#include "DialogSystemCharacter.h"
//////////////////////////////////////////////////////////////////////////
// ADialogSystemCharacter
void ADialogSystemCharacter::ToggleTalking()
{
if (bIsInTalkRange)
{
//If we are in talk range handle the talk status and the UI
bIsTalking = !bIsTalking;
ToggleUI();
if (bIsTalking && AssociatedPawn)
{
//It is more polite to face the person you talk to!
FVector Location = AssociatedPawn->GetActorLocation();
FVector TargetLocation = GetActorLocation();
AssociatedPawn->SetActorRotation((TargetLocation - Location).Rotation());
}
}
}
FDialog* ADialogSystemCharacter::RetrieveDialog(UDataTable* TableToSearch, FName RowName)
{
if(!TableToSearch) return nullptr;
//The table is valid - retrieve the given row if possible
FString ContextString;
return TableToSearch->FindRow<FDialog>(RowName, ContextString);
}
void ADialogSystemCharacter::GeneratePlayerLines(UDataTable& PlayerLines)
{
//Get all the row names of the table
TArray<FName> PlayerOptions = PlayerLines.GetRowNames();
//For each row name try to retrieve the contents of the table
for (auto It : PlayerOptions)
{
//Retrieve the contents of the table
FDialog* Dialog = RetrieveDialog(&PlayerLines, It);
if (Dialog)
{
//We retrieved a valid row - populate the questions array with our excerpts
Questions.Add(Dialog->QuestionExcerpt);
}
}
//Make sure to create a reference of the available line for later use
AvailableLines = &PlayerLines;
}
void ADialogSystemCharacter::Talk(FString Excerpt, TArray<FSubtitle>& Subtitles)
{
//Get all the row names based on our stored lines
TArray<FName> PlayerOptions = AvailableLines->GetRowNames();
for (auto It : PlayerOptions)
{
//Search inside the available lines table to find the pressed Excerpt from the UI
FDialog* Dialog = RetrieveDialog(AvailableLines, It);
if (Dialog && Dialog->QuestionExcerpt == Excerpt)
{
//We've found the pressed excerpt - assign our sfx to the audio comp and play it
AudioComp->SetSound(Dialog->SFX);
AudioComp->Play();
//Update the corresponding subtitles
Subtitles = Dialog->Subtitles;
if (UI && AssociatedPawn && Dialog->bShouldAIAnswer)
{
//Calculate the total displayed time for our subtitles
//When the subtitles end - the associated pawn will be able to talk to our character
TArray<FSubtitle> SubtitlesToDisplay;
float TotalSubsTime = 0.f;
for (int32 i = 0; i < Subtitles.Num(); i++)
{
TotalSubsTime += Subtitles[i].AssociatedTime;
}
//Just a hardcoded value in order for the AI not to answer right after our subs.
//It would be better if we expose that to our editor? Sure!
TotalSubsTime += 1.f;
//Tell the associated pawn to answer to our character after the specified time!
AssociatedPawn->AnswerToCharacter(It, SubtitlesToDisplay, TotalSubsTime);
}
else if (!Dialog->bShouldAIAnswer) ToggleTalking();
break;
}
}
}
ADialogSystemCharacter::ADialogSystemCharacter()
{
// Set size for collision capsule
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// set our turn rates for input
BaseTurnRate = 45.f;
BaseLookUpRate = 45.f;
// Don't rotate when the controller rotates. Let that just affect the camera.
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...
GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
GetCharacterMovement()->JumpZVelocity = 600.f;
GetCharacterMovement()->AirControl = 0.2f;
// Create a camera boom (pulls in towards the player if there is a collision)
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->AttachTo(RootComponent);
CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character
CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller
// Create a follow camera
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->AttachTo(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm
bIsTalking = false;
bIsInTalkRange = false;
AssociatedPawn = nullptr;
AudioComp = CreateDefaultSubobject<UAudioComponent>(FName("AudioComp"));
AudioComp->AttachTo(GetRootComponent());
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)
}
//////////////////////////////////////////////////////////////////////////
// Input
void ADialogSystemCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
// Set up gameplay key bindings
check(InputComponent);
InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
InputComponent->BindAxis("MoveForward", this, &ADialogSystemCharacter::MoveForward);
InputComponent->BindAxis("MoveRight", this, &ADialogSystemCharacter::MoveRight);
InputComponent->BindAction("Talk", IE_Pressed, this, &ADialogSystemCharacter::ToggleTalking);
// We have 2 versions of the rotation bindings to handle different kinds of devices differently
// "turn" handles devices that provide an absolute delta, such as a mouse.
// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
InputComponent->BindAxis("TurnRate", this, &ADialogSystemCharacter::TurnAtRate);
InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
InputComponent->BindAxis("LookUpRate", this, &ADialogSystemCharacter::LookUpAtRate);
// handle touch devices
InputComponent->BindTouch(IE_Pressed, this, &ADialogSystemCharacter::TouchStarted);
InputComponent->BindTouch(IE_Released, this, &ADialogSystemCharacter::TouchStopped);
}
void ADialogSystemCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
// jump, but only on the first touch
if (FingerIndex == ETouchIndex::Touch1)
{
Jump();
}
}
void ADialogSystemCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
if (FingerIndex == ETouchIndex::Touch1)
{
StopJumping();
}
}
void ADialogSystemCharacter::TurnAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void ADialogSystemCharacter::LookUpAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
void ADialogSystemCharacter::MoveForward(float Value)
{
if ((Controller != NULL) && (Value != 0.0f) && !bIsTalking)
{
// find out which way is forward
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get forward vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}
void ADialogSystemCharacter::MoveRight(float Value)
{
if ( (Controller != NULL) && (Value != 0.0f) && !bIsTalking )
{
// find out which way is right
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get right vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// add movement in that direction
AddMovementInput(Direction, Value);
}
}