Agrarsense
Spectator.cpp
Go to the documentation of this file.
1// Copyright (c) 2023 FrostBit Software Lab at the Lapland University of Applied Sciences
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
6#include "Spectator.h"
7#include "GameFramework/FloatingPawnMovement.h"
8#include "GameFramework/PlayerController.h"
9#include "Components/SceneComponent.h"
10#include "NiagaraFunctionLibrary.h"
11#include "NiagaraSystem.h"
12
16
18{
19 Super::BeginPlay();
20
21 // Load and setup rain/snow fall niagara system for this spectator
22 UNiagaraSystem* NiagaraSystem = LoadObject<UNiagaraSystem>(nullptr, TEXT("/Game/Agrarsense/Particles/WaterAndSnow/NS_Particles.NS_Particles"));
23 if (NiagaraSystem)
24 {
25 NiagaraComponent = UNiagaraFunctionLibrary::SpawnSystemAttached(NiagaraSystem, this->GetRootComponent(),
26 FName("NiagaraEmitterSocketName"),
27 FVector(0.0, 0.0, 150.0f), FRotator::ZeroRotator, EAttachLocation::KeepRelativeOffset, true);
28
29 ASensor::HideComponentForAllCameras(Cast<UPrimitiveComponent>(NiagaraComponent));
30 }
31
32 // Disable niagara component
34
35 FVector RelativePosition = FVector(0.0f, 0.0f, 0.0f);
36 float OverlapBoundsSize = 15.0f;
37
38 // Create OverlapSensor
40 Params.OwningActor = this;
41 Params.Size = FVector(OverlapBoundsSize, OverlapBoundsSize, OverlapBoundsSize);
42 Params.RelativePosition = RelativePosition;
43 Params.AllChannels = true;
44 FString OverlapSensorID = "spectator/overlap";
45 OverlapSensor = USensorFactory::SpawnOverlapSensor(GetActorTransform(), Params, OverlapSensorID, "overlap", this);
46}
47
48void ASpectator::EndPlay(const EEndPlayReason::Type EndPlayReason)
49{
50 Super::EndPlay(EndPlayReason);
51
53 {
54 NiagaraComponent->UnregisterComponent();
55 NiagaraComponent->DestroyComponent();
56 NiagaraComponent = nullptr;
57 }
58
59 if (OverlapSensor)
60 {
61 OverlapSensor->Destroy();
62 OverlapSensor = nullptr;
63 }
64
65 Target.Reset();
66}
67
68void ASpectator::TeleportSpectator(const FTransform& Transform)
69{
70 if (!IsPlayerControlled())
71 {
72 return;
73 }
74
75 // Detach from any Actor and enable inputs.
77
78 FVector TargetLocation = Transform.GetLocation();
79 FVector Direction = GetActorLocation() - TargetLocation;
80 Direction.Normalize();
81
82 // 20 units away from the target so we are not top if it..
83 FVector NewLocation = TargetLocation + Direction * 20.0f;
84
85 FRotator NewRotation = (TargetLocation - NewLocation).ToOrientationRotator();
86
87 SetActorLocationAndRotation(NewLocation, NewRotation);
88
89 // Set the player controller rotation to match the incoming Transform angle,
90 // This actually sets the camera angle.
91 APlayerController* PlayerController = Cast<APlayerController>(GetController());
92 if (PlayerController)
93 {
94 PlayerController->SetControlRotation(Transform.Rotator());
95 }
96}
97
98void ASpectator::TeleportToActorLocation(const AActor* Actor)
99{
100 if (Actor)
101 {
102 FTransform Transform = Actor->GetActorTransform();
104 }
105}
106
107void ASpectator::FollowActor(AActor* Actor, bool DisableInputs, const float DistanceToActor, const float HeightOffset)
108{
109 Target = Actor;
110
111 if (!Target.IsValid())
112 {
113 return;
114 }
115
116 // Detach from any previous target
117 DetachFromActor(FDetachmentTransformRules::KeepRelativeTransform);
118
119 // Set the offset to position the spectator slightly above and behind the actor
120 FVector Offset = FVector(0.0f, 0.0f, HeightOffset);
121
122 FVector TargetActorLocation = Actor->GetActorLocation();
123
124 FVector DirectionToActor = TargetActorLocation - GetActorLocation();
125 DirectionToActor.Normalize();
126
127 // Face the camera slightly down toward the actor
128 APlayerController* PlayerController = Cast<APlayerController>(GetController());
129 if (PlayerController)
130 {
131 if (DisableInputs)
132 {
133 DisableInput(PlayerController);
134 }
135 FRotator NewRotation = DirectionToActor.ToOrientationRotator();
136 PlayerController->SetControlRotation(NewRotation);
137 }
138
139 // Calculate the new location to be closer behind the actor
140 FVector NewLocation = TargetActorLocation + DirectionToActor * -DistanceToActor + Offset;
141
142 // Attach to the new target actor's root component with the offset
143 USceneComponent* Root = Actor->GetRootComponent();
144 if (Root)
145 {
146 AttachToComponent(Root, FAttachmentTransformRules::KeepRelativeTransform);
147 SetActorLocation(NewLocation);
148 }
149
150 OnFollowTargetChanged.Broadcast(true, Target.Get());
151}
152
153void ASpectator::TeleportToFollowLocation(FVector TargetLocation, const float DistanceToLocation, const float HeightOffset)
154{
155 // Set the offset to position the spectator slightly above and behind the actor
156 FVector Offset = FVector(0.0f, 0.0f, HeightOffset);
157
158 FVector DirectionToActor = TargetLocation - GetActorLocation();
159 DirectionToActor.Normalize();
160
161 // Face the camera slightly down toward the actor
162 APlayerController* PlayerController = Cast<APlayerController>(GetController());
163 if (PlayerController)
164 {
165 FRotator NewRotation = DirectionToActor.ToOrientationRotator();
166 PlayerController->SetControlRotation(NewRotation);
167 }
168
169 // Calculate the new location to be closer behind the actor
170 FVector NewLocation = TargetLocation + DirectionToActor * -DistanceToLocation + Offset;
171
172 SetActorLocation(NewLocation);
173}
174
175void ASpectator::TeleportToActorFollowLocation(AActor* Actor, const float DistanceToActor, const float HeightOffset)
176{
177 if (!IsValid(Actor))
178 {
179 return;
180 }
181
182 FVector TargetLocation = Actor->GetActorLocation();
183
184 TeleportToFollowLocation(TargetLocation, DistanceToActor, HeightOffset);
185}
186
188{
189 // Detach from any previous target
190 DetachFromActor(FDetachmentTransformRules::KeepRelativeTransform);
191
192 Target.Reset();
193
194 if (EnableInputs)
195 {
196 APlayerController* PlayerController = Cast<APlayerController>(GetController());
197
198 if (PlayerController)
199 {
200 EnableInput(PlayerController);
201 }
202 }
203
204 OnFollowTargetChanged.Broadcast(false, Target.Get());
205}
206
208{
210 {
211 NiagaraComponent->SetVisibility(Visible);
212 }
213}
214
215void ASpectator::SetMaxSpeed(float MaxSpeed)
216{
217 UFloatingPawnMovement* FloatingMovement = GetFloatingPawnMovement();
218 if (FloatingMovement)
219 {
220 FloatingMovement->MaxSpeed = MaxSpeed;
221 }
222}
223
225{
226 UFloatingPawnMovement* FloatingMovement = GetFloatingPawnMovement();
227 if (FloatingMovement)
228 {
229 return FloatingMovement->MaxSpeed;
230 }
231
232 // Else return default value of 1500.0f (set in BP_spectator blueprint)
233 return 1500.0f;
234}
235
237{
238 return Cast<UFloatingPawnMovement>(GetMovementComponent());
239}
240
241
243{
244
245 if (!IsPlayerControlled())
246 {
247 return;
248 }
249
250 FTransform Transform = TeleportLocation.TeleportLocationTransform;
251
252 // Detach from any Actor and enable inputs.
254
255 SetActorLocationAndRotation(Transform.GetLocation(), Transform.GetRotation().Rotator());
256
257 // Set the player controller rotation to match the incoming Transform angle,
258 // This actually sets the camera angle.
259 APlayerController* PlayerController = Cast<APlayerController>(GetController());
260 if (PlayerController)
261 {
262 PlayerController->SetControlRotation(Transform.Rotator());
263 }
264}
static void HideComponentForAllCameras(UPrimitiveComponent *PrimitiveComponent)
Definition: Sensor.cpp:308
void SetMaxSpeed(float MaxSpeed=1500.0f)
Definition: Spectator.cpp:215
AOverlapSensor * OverlapSensor
Definition: Spectator.h:158
void TeleportToActorFollowLocation(AActor *Actor, const float DistanceToActor=1500.0f, const float HeightOffset=500.0f)
Definition: Spectator.cpp:175
void TeleportToFollowLocation(FVector TargetLocation, const float DistanceToLocation, const float HeightOffset)
Definition: Spectator.cpp:153
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
Definition: Spectator.cpp:48
float GetMaxSpeed()
Definition: Spectator.cpp:224
void StopFollowingAnyActor(bool EnableInputs=true)
Definition: Spectator.cpp:187
FFollowTargetChanged OnFollowTargetChanged
Definition: Spectator.h:146
void FollowActor(AActor *Actor, bool DisableInputs=true, const float DistanceToActor=150.0f, const float HeightOffset=10.0f)
Definition: Spectator.cpp:107
void TeleportToActorLocation(const AActor *Actor)
Definition: Spectator.cpp:98
TWeakObjectPtr< AActor > Target
Definition: Spectator.h:162
UNiagaraComponent * NiagaraComponent
Definition: Spectator.h:155
UFloatingPawnMovement * GetFloatingPawnMovement()
Definition: Spectator.cpp:236
void SetNiagaraComponentVisibility(bool Visible)
Definition: Spectator.cpp:207
virtual void BeginPlay() override
Definition: Spectator.cpp:17
void TeleportSpectator(const FTransform &Transform)
Definition: Spectator.cpp:68
void TeleportToLevelTeleportLocation(FLevelTeleportLocation TeleportLocation)
Definition: Spectator.cpp:242
static AOverlapSensor * SpawnOverlapSensor(const FTransform &transform, FOverlapSensorParameters Parameters, const FString sensorIdentifier, const FString sensorName, AActor *Parent=nullptr)