Documentation for the Unreal C++ Plugin
Loading...
Searching...
No Matches
PixoVRTeleporter.cpp
Go to the documentation of this file.
1// Copyright(c) Pixo Group. All Rights Reserved.
2
4#include "Components/StaticMeshComponent.h"
5#include "Components/WidgetInteractionComponent.h"
6#include "Kismet/GameplayStatics.h"
7#include "NavigationSystem.h"
8#include "VRExpansionFunctionLibrary.h"
9#include "PixoVRCharacter.h"
12#include "Kismet/KismetMathLibrary.h"
13
14#define TELEPORT_DEBUG 0
15
16DEFINE_LOG_CATEGORY(LogPixoVRTeleporter);
17
19 : TeleportCylinder(nullptr)
20 , Ring(nullptr)
21 , bDrawTeleportCylinder(true)
22 , TeleportFadeColor(FLinearColor::Black)
23 , NavigationSystem(nullptr)
24{
25 static ConstructorHelpers::FObjectFinder<UStaticMesh> CylinderMeshFinder(TEXT("StaticMesh'/PixoCore/Meshes/BasicShapes/Cylinder.Cylinder'"));
26 UStaticMesh* CylinderMesh = CylinderMeshFinder.Object;
27
28 static ConstructorHelpers::FObjectFinder<UStaticMesh> CylinderRingMeshFinder(TEXT("StaticMesh'/PixoCore/Meshes/Controller/SM_FatCylinder.SM_FatCylinder'"));
29 UStaticMesh* CylinderRingMesh = CylinderRingMeshFinder.Object;
30
31 static ConstructorHelpers::FObjectFinder<UMaterialInstance> TeleportCylinderMaterialFinder(TEXT("MaterialInstanceConstant'/PixoCore/Materials/Controller/TeleportCylinderPreviewMaterialInstance.TeleportCylinderPreviewMaterialInstance'"));
32 UMaterialInstance* CylinderMaterial = TeleportCylinderMaterialFinder.Object;
33
34 static ConstructorHelpers::FObjectFinder<UMaterial> ArcEndPointMaterialFinder(TEXT("Material'/PixoCore/Materials/Controller/ArcEndpointMaterial.ArcEndpointMaterial'"));
35 UMaterial* ArcEndPointMaterial = ArcEndPointMaterialFinder.Object;
36
37 // Teleport Cylinder.
38 TeleportCylinder = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TeleportCylinder"));
39 TeleportCylinder->SetupAttachment(RootComponent);
40 TeleportCylinder->SetWorldScale3D(FVector(0.75f, 0.75f, 1.0f));
41 TeleportCylinder->SetStaticMesh(CylinderMesh);
42 TeleportCylinder->SetMaterial(0, CylinderMaterial);
43 TeleportCylinder->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
44 TeleportCylinder->SetGenerateOverlapEvents(false);
45 TeleportCylinder->SetAbsolute(true, true, true);
46
47 // Teleport Cylinder Ring.
48 Ring = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Ring"));
49 Ring->SetupAttachment(TeleportCylinder);
50 Ring->SetRelativeScale3D(FVector(0.5f, 0.5f, 0.15f));
51 Ring->SetStaticMesh(CylinderRingMesh);
52 Ring->SetMaterial(0, ArcEndPointMaterial);
53 Ring->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
54 Ring->SetGenerateOverlapEvents(false);
55}
56
58{
59 Super::ActivateTeleporter(InActivate);
60
61 // Hide/Show the teleport cylinder.
63 {
64 TeleportCylinder->SetVisibility(InActivate, true);
65 }
66}
67
69{
70 Super::BeginPlay();
71
72 TeleportCylinder->SetVisibility(false, true);
73
74 NavigationSystem = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
75}
76
78{
79 TArray<FVector> TracePoints;
80
81 // Is the location of the projectile falling onto the ground.
82 FVector TraceLocation;
83
84 // The projects location will be mapped to the Nav Mesh location.
85 FVector NavMeshLocation;
86
87 bIsValidTeleportDestination = TraceTeleportDestination(TracePoints, TraceLocation, NavMeshLocation);
88
90 {
92 }
93
95 {
97 }
98
101
102 // We prepare the rotation of the teleport cylinder.
103 if(PadRotation != FRotator::ZeroRotator)
104 {
105 // User changed rotation using the otion Controller Pad.
107 }
108 else
109 {
110 // If we don't have any Motion Controller Pad rotation, set pitch and roll to zero.
111 // and use previous Yaw rotation.
112 TeleportRotation.Pitch = 0.0f;
113 TeleportRotation.Roll = 0.0f;
114 }
115
116#if TELEPORT_DEBUG
117 // The following lines can be all deleted. It exists only for debug purpose.
118 FVector DevicePosition = FVector::ZeroVector;
119 FRotator DeviceRotation = FRotator::ZeroRotator;
120 UHeadMountedDisplayFunctionLibrary::GetOrientationAndPosition(DeviceRotation, DevicePosition);
121 DevicePosition.Z = 0.0f;
122 FVector Correction = UKismetMathLibrary::GreaterGreater_VectorRotator(DevicePosition, TeleportRotation);
123
124 FVector HMDPositionInWorldSpace = GetOwner()->GetActorLocation() - DevicePosition;
125 APixoVRCharacter* PixoVRCharacter = Cast<APixoVRCharacter>(GetOwner());
126 HMDPositionInWorldSpace = PixoVRCharacter->GetVRLocation();
127 HMDPositionInWorldSpace.Z = 30.0f;
128 FVector OwnerActorLocation = GetOwner()->GetActorLocation();
129 OwnerActorLocation.Z += 10.0f;
130 UKismetSystemLibrary::DrawDebugLine(this, OwnerActorLocation, TeleportCylinder->GetComponentLocation(), FColor::Red, 0.0f, 2.0f);
131 UKismetSystemLibrary::DrawDebugLine(this, OwnerActorLocation, HMDPositionInWorldSpace, FColor::Green, 0.0f, 2.0f);
132#endif
133}
134
135bool APixoVRTeleporter::TraceTeleportDestination(TArray<FVector>& TracePoints, FVector& TraceLocation, FVector& NavMeshLocation)
136{
137 FVector StartPos(FVector::ZeroVector);
138 FVector LaunchVelocity (FVector::ZeroVector);
139
140 GetTeleportationTransform(StartPos, LaunchVelocity);
141 LaunchVelocity *= TeleportLaunchVelocity;
142
143 TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
144 ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldStatic));
145
146 FPredictProjectilePathParams Params;
147 Params.bTraceWithCollision = true;
148 Params.bTraceComplex = false;
149 Params.DrawDebugType = EDrawDebugTrace::None;
150 Params.DrawDebugTime = 0.0f;
151 Params.SimFrequency = 30.0f;
152 Params.OverrideGravityZ = 0.0f;
153 Params.ObjectTypes = ObjectTypes;
154 Params.bTraceWithChannel = false;
155 Params.ProjectileRadius = 0.0f;
156 Params.StartLocation = StartPos;
157 Params.MaxSimTime = 2.0f;
158 Params.LaunchVelocity = LaunchVelocity;
159
160 FPredictProjectilePathResult PredictResult;
161 bool bHit = UGameplayStatics::PredictProjectilePath(this, Params, PredictResult);
162
163 FHitResult HitResult;
164 FVector LastTraceDestination;
165
166 HitResult = PredictResult.HitResult;
167 LastTraceDestination = PredictResult.LastTraceDestination.Location;
168 TracePoints.Empty(PredictResult.PathData.Num());
169
170 for (const FPredictProjectilePathPointData& PathPoint : PredictResult.PathData)
171 {
172 TracePoints.Add(PathPoint.Location);
173 }
174
175 TraceLocation = HitResult.Location;
176
177 bool bProjectPointToNavigation = false;
179 {
180 FVector QueryingExtent (500.0f, 500.0f, 500.0f);
181 FNavLocation NavLocation {};
182
183 bProjectPointToNavigation = NavigationSystem->ProjectPointToNavigation(HitResult.Location, NavLocation, QueryingExtent);
184 NavMeshLocation = NavLocation.Location;
185 }
186
187 bProjectPointToNavigation = (NavMeshLocation != FVector(0.0f, 0.0f, 0.0f)) && (TraceLocation != NavMeshLocation);
188
189 return bHit & bProjectPointToNavigation;
190}
191
192void APixoVRTeleporter::UpdateTeleportCylinder(const FVector& NavMeshLocation, bool ValidLocationFound)
193{
194 if(ValidLocationFound)
195 {
196 const auto Start = NavMeshLocation;
197 const auto End = Start + FVector(0.0f, 0.0f, -200.0f);
198 TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
199 ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldStatic));
200 const auto TraceComplex = false;
201 const TArray<AActor*> ActorsToIgnore;
202 const auto IgnoreSelf = true;
203 FHitResult HitResult;
204 const float DrawTime = 5.0;
205
206 UKismetSystemLibrary::LineTraceSingleForObjects(this,
207 Start,
208 End,
209 ObjectTypes,
210 TraceComplex,
211 ActorsToIgnore,
212 EDrawDebugTrace::None,
213 HitResult,
214 IgnoreSelf,
215 FLinearColor::Red,
216 FLinearColor::Green,
217 DrawTime);
218
219 FVector NewLocation = FVector::ZeroVector;
220 if(HitResult.bBlockingHit)
221 {
222 NewLocation = HitResult.ImpactPoint;
223 }
224 else
225 {
226 NewLocation = NavMeshLocation;
227 }
228
229 TeleportCylinder->SetWorldLocation(NewLocation, false, nullptr, ETeleportType::TeleportPhysics);
230 }
231 else
232 {
233 // TODO Do we want to do something here if we have no valid location?
234 }
235}
236
237#if WITH_EDITOR
238void APixoVRTeleporter::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
239{
240 if(PropertyChangedEvent.Property != nullptr)
241 {
242 const FName PropertyName (PropertyChangedEvent.Property->GetFName());
243 if(PropertyName == GET_MEMBER_NAME_CHECKED(APixoVRTeleporter, bDrawTeleportArrow))
244 {
245 Arrow->SetVisibility(bDrawTeleportArrow, false);
246 }
247 }
248
249 Super::PostEditChangeProperty(PropertyChangedEvent);
250}
251#endif
252
253void APixoVRTeleporter::ExecuteTeleportation(UVRBaseCharacterMovementComponent* InMovementComponent, const FTransform& ActorTransform, const FVector& VRLocation, const FRotator& ActorRotation)
254{
255 // If we don't have a valid destination, don't execute teleportation.
257 {
258 return;
259 }
260
261 APixoVRCharacter* PixoVRCharacter = Cast<APixoVRCharacter>(GetOwner());
262 if (PixoVRCharacter)
263 {
264 if (PixoVRCharacter->bTeleportSoundsEnabled && PixoVRCharacter->TeleportSoundCue)
265 {
266 UGameplayStatics::PlaySound2D(this, PixoVRCharacter->TeleportSoundCue);
267 }
268 }
269
270 MovementComponent = InMovementComponent;
271
272 const FVector PivotPoint = VRLocation;
273 const FVector InvPivotPoint = UKismetMathLibrary::InverseTransformLocation(ActorTransform, PivotPoint);
274
275 const FVector LastValidTeleportLocation = TeleportCylinder->GetComponentLocation();
276 const FVector TeleportToLocation = GetTeleportDestination(LastValidTeleportLocation);
277
278 UVRExpansionFunctionLibrary::RotateAroundPivot(FRotator::ZeroRotator, TeleportToLocation, ActorRotation, InvPivotPoint, TimedLocation, TimedRotation, true);
279
280 auto FadeInFinishedEvent = [this]()
281 {
282 MovementComponent->PerformMoveAction_Teleport(TimedLocation, TimedRotation);
283 };
284
285 EventLogService::NewEvent<UFadeInAndFadeOutEvent>(nullptr, FadeInFinishedEvent, nullptr, FadeInDuration, 0.0f, FadeOutDuration);
286}
DEFINE_LOG_CATEGORY(LogPixoVRTeleporter)
Pixo VR Character This class represents the main character in the Pixo VR game. It extends the AVRCha...
USoundCue * TeleportSoundCue
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "PixoVR", meta = (EditCondition = "bTeleportSo...
bool bTeleportSoundsEnabled
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "PixoVR")
Class for VR teleporter functionality. It allows teleportation using visual indicators.
virtual void BeginPlay() override
virtual void TickTeleporter(float DeltaTime) override
Tick the Teleporter.
virtual void ExecuteTeleportation(UVRBaseCharacterMovementComponent *MovementComponent, const FTransform &ActorTransform, const FVector &VRLocation, const FRotator &ActorRotation) override
Execute the teleportation. It checks if there is a valid teleport destination before executing the te...
bool bDrawTeleportCylinder
UPROPERTY(EditAnywhere, Category = "PixoVR | Teleporter")
virtual void ActivateTeleporter(bool InActivate) override
Activate or deactivate the Teleporter.
UStaticMeshComponent * TeleportCylinder
UPROPERTY(VisibleDefaultsOnly, BlueprintReadWrite)
UStaticMeshComponent * Ring
UPROPERTY(VisibleDefaultsOnly, BlueprintReadWrite)
UVRBaseCharacterMovementComponent * MovementComponent
void UpdateTeleportCylinder(const FVector &NewLocation, bool ValidLocationFound)
Update the teleport cylinder.
bool TraceTeleportDestination(TArray< FVector > &TracePoints, FVector &TraceLocation, FVector &NavMeshLocation)
Traces the teleport destination using projectile path prediction and navigation system....
UNavigationSystemV1 * NavigationSystem
float TeleportLaunchVelocity
UPROPERTY(EditAnywhere, Category = "PixoVR | Teleporter")
bool bIsValidTeleportDestination
UPROPERTY(BlueprintReadOnly, Category = "PixoVR | Teleporter")
FRotator TimedRotation
UStaticMeshComponent * Arrow
UPROPERTY(VisibleDefaultsOnly, BlueprintReadWrite)
FRotator PadRotation
UPROPERTY(BlueprintReadOnly, Category = "PixoVR | Teleporter")
float FadeInDuration
UPROPERTY(EditAnywhere, Category = "PiUpdateMotionControllerRotationxoVR | Teleporter")
bool bDrawTeleportArrow
UPROPERTY(EditAnywhere, Category = "PixoVR | Teleporter")
float FadeOutDuration
UPROPERTY(EditAnywhere, Category = "PixoVR | Teleporter")
virtual void FVector GetTeleportDestination(const FVector &OriginalLocation)
Get the teleport destination.
void GetTeleportationTransform(FVector &Location, FVector &ForwardVector)
Get the teleportation transform which includes location and orientation.
virtual void UpdateArcEndpoint(const FVector &NewLocation, bool ValidLocationFound)
Update the endpoint of the arc spline.
virtual void UpdateArcSpline(TArray< FVector > &SplinePoints, bool ValidLocationFound)
Update the arc spline.
FRotator TeleportRotation
UPROPERTY(BlueprintReadOnly, Category = "PixoVR | Teleporter")
bool bDrawArcSpline
UPROPERTY(EditAnywhere, Category = "PixoVR | Teleporter")
static FUNCTION_NON_NULL_RETURN_START TEventType * NewEvent(APlayerController *Executor=nullptr) FUNCTION_NON_NULL_RETURN_END
Creates a new event of the specified type.