Skip to content
Snippets Groups Projects
Commit 73269499 authored by Kris Tabea Helwig's avatar Kris Tabea Helwig
Browse files

Merge branch 'feature/PointsOfInterest' into '5.4'

Implements `PointOfInterest`s

See merge request vr-vis/VR-Group/unreal-development/plugins/rwth-vr-quick-start!1
parents 2cc785ce b6bff74b
Branches
No related tags found
1 merge request!1Implements `PointOfInterest`s
File added
File added
#include "PointOfInterest.h"
#include "Logging/StructuredLog.h"
#include "Components/BillboardComponent.h"
DEFINE_LOG_CATEGORY(POILog)
APointOfInterest::APointOfInterest()
{
UE_LOGFMT(POILog, Verbose, "POI instantiated");
SetRootComponent(CreateDefaultSubobject<USceneComponent>("SceneComponent"));
auto Billboard = CreateDefaultSubobject<UBillboardComponent>("BillboardComponent");
static ConstructorHelpers::FObjectFinder<UTexture2D> LocationMarker(TEXT("/Script/Engine.Texture2D'/RWTHVRQuickStart/location_marker.location_marker'"));
if(LocationMarker.Succeeded())
{
Billboard->SetSprite(LocationMarker.Object);
}
else
{
UE_LOGFMT(POILog, Verbose, "POILog: Could not find location marker Texture. The Asset might have moved.");
}
Billboard->SetupAttachment(RootComponent);
Billboard->SetHiddenInGame(true);
Billboard->SetWorldScale3D(FVector(0.1f, 0.1f, 0.1f));
}
#include "PointOfInterestManager.h"
#include "PointOfInterest.h"
#include "GameFramework/PlayerStart.h"
#include "Kismet/GameplayStatics.h"
#include "Logging/StructuredLog.h"
DEFINE_LOG_CATEGORY(POIManagerLog);
APointOfInterestManager::APointOfInterestManager()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bStartWithTickEnabled = true;
PrimaryActorTick.SetTickFunctionEnable(true);
POIs = TArray<APointOfInterest*>();
SplineComponent = CreateDefaultSubobject<USplineComponent>("SplineComponent");
SplineComponent->SetupAttachment(RootComponent.Get());
}
void APointOfInterestManager::TickActor(float DeltaTime, enum ELevelTick TickType, FActorTickFunction& ThisTickFunction)
{
SplineComponent->Duration = SplineComponent->GetSplineLength() / CameraSpeed;
if (IsRidingCamera)
{
ProgressCameraRide();
}
}
void APointOfInterestManager::ResetToPlayerStart()
{
APawn* Pawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
if (!Pawn)
{
UE_LOGFMT(POIManagerLog, Warning, "Attempted to move player pawn to PlayerStart but no pawn found to move.");
return;
}
TArray<AActor*> AllPlayerStarts;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), APlayerStart::StaticClass(), AllPlayerStarts);
if (AllPlayerStarts.IsEmpty())
{
UE_LOGFMT(POIManagerLog, Warning, "Attempted to move player pawn to PlayerStart but no PlayerStart found to move.");
return;
}
AActor* PlayerStart = AllPlayerStarts[0];
Pawn->Controller->SetControlRotation(PlayerStart->GetActorRotation());
Pawn->SetActorLocationAndRotation(PlayerStart->GetActorLocation(), PlayerStart->GetActorRotation());
}
void APointOfInterestManager::AddPointOfInterest()
{
APointOfInterest* POI = static_cast<APointOfInterest*>(GetWorld()->SpawnActor(APointOfInterest::StaticClass()));
POI->GetRootComponent()->TransformUpdated.AddLambda([this](USceneComponent*, EUpdateTransformFlags, ETeleportType)
{
UpdateSpline();
});
POIs.Add(POI);
UpdateSpline();
}
void APointOfInterestManager::VisitNextPointOfInterest()
{
if (CurrentPOIIndex >= GetPointOfInterestCount() - 1)
{
CurrentPOIIndex = 0;
}
else
{
++CurrentPOIIndex;
}
VisitPointOfInterest(POIs[CurrentPOIIndex]);
}
void APointOfInterestManager::VisitPreviousPointOfInterest()
{
if (CurrentPOIIndex <= 0)
{
CurrentPOIIndex = GetPointOfInterestCount() - 1;
}
else
{
--CurrentPOIIndex;
}
VisitPointOfInterest(POIs[CurrentPOIIndex]);
}
void APointOfInterestManager::VisitPointOfInterestByIndex(int index)
{
VisitPointOfInterest(POIs[index]);
}
void APointOfInterestManager::VisitPointOfInterest(APointOfInterest* POI) const
{
APawn* Pawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
if (!Pawn)
{
UE_LOGFMT(POIManagerLog, Warning, "Attempted to move player pawn but no pawn found to move.");
return;
}
FVector Location = POI->GetActorLocation();
FRotator Rotation = POI->GetActorRotation();
Rotation.Pitch = 0;
Rotation.Roll = 0;
Pawn->Controller->SetControlRotation(Rotation);
Pawn->SetActorLocationAndRotation(Location, Rotation);
}
int APointOfInterestManager::GetPointOfInterestCount()
{
return POIs.Num();
}
void APointOfInterestManager::StartCameraRide()
{
CameraRideStart = UGameplayStatics::GetTimeSeconds(this);
CameraRideEnd = CameraRideStart + SplineComponent->Duration;
CurrentUpdate = 0;
DurationInUpdates = static_cast<int>(SplineComponent->Duration * CameraRideSecondsToUpdates);
IsRidingCamera = true;
}
void APointOfInterestManager::StopCameraRide()
{
CameraRideEnded();
}
void APointOfInterestManager::UpdateSpline()
{
for (int i = 0; i < GetPointOfInterestCount(); ++i)
{
if (POIs[i] == nullptr)
{
POIs.RemoveAt(i);
SplineComponent->RemoveSplinePoint(i);
--i;
}
else if (!POIs[i]->GetRootComponent()->TransformUpdated.IsBound())
{
POIs[i]->GetRootComponent()->TransformUpdated.AddLambda(
[this](USceneComponent*, EUpdateTransformFlags, ETeleportType)
{
UpdateSpline();
});
}
}
int POIsNum = GetPointOfInterestCount();
int SplinePointsNum = SplineComponent->GetNumberOfSplinePoints();
if (POIsNum > SplinePointsNum)
{
for (int i = SplinePointsNum; i < POIsNum; ++i)
{
SplineComponent->AddSplinePointAtIndex(FVector::Zero(), i, ESplineCoordinateSpace::World);
}
}
else if (POIsNum < SplinePointsNum)
{
for (int i = SplinePointsNum - 1; i >= POIsNum; --i)
{
SplineComponent->RemoveSplinePoint(i);
}
}
for (int i = 0; i < GetPointOfInterestCount(); ++i)
{
APointOfInterest* POI = POIs[i];
FVector POIPosition = POI->GetActorLocation();
FRotator POIRotation = POI->GetActorRotation();
SplineComponent->SetLocationAtSplinePoint(i, POIPosition, ESplineCoordinateSpace::World);
SplineComponent->SetRotationAtSplinePoint(i, POIRotation, ESplineCoordinateSpace::World);
}
}
void APointOfInterestManager::ProgressCameraRide()
{
double Current = UGameplayStatics::GetTimeSeconds(this);
float SecondsSinceStart = Current - CameraRideStart;
CurrentUpdate++;
APawn* Pawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
if (!Pawn)
{
UE_LOGFMT(POIManagerLog, Warning, "Attempted to move player pawn but no pawn found to move.");
return;
}
if (MakeCameraRideProgressionConstantBetweenTicks)
{
if (CurrentUpdate < DurationInUpdates)
{
float CurrentTime = 1.0f * CurrentUpdate / CameraRideSecondsToUpdates;
FVector Location = SplineComponent->GetLocationAtTime(CurrentTime, ESplineCoordinateSpace::World);
FRotator Rotation = SplineComponent->GetRotationAtTime(CurrentTime, ESplineCoordinateSpace::World);
Rotation.Pitch = 0;
Rotation.Roll = 0;
Pawn->Controller->SetControlRotation(Rotation);
Pawn->SetActorLocationAndRotation(Location, Rotation);
}
else
{
CameraRideEnded();
}
}
else
{
if (Current < CameraRideEnd)
{
FVector Location = SplineComponent->GetLocationAtTime(SecondsSinceStart, ESplineCoordinateSpace::World);
FRotator Rotation = SplineComponent->GetRotationAtTime(SecondsSinceStart, ESplineCoordinateSpace::World);
Rotation.Pitch = 0;
Rotation.Roll = 0;
Pawn->Controller->SetControlRotation(Rotation);
Pawn->SetActorLocationAndRotation(Location, Rotation);
}
else
{
CameraRideEnded();
}
}
}
void APointOfInterestManager::CameraRideEnded()
{
IsRidingCamera = false;
VisitPointOfInterestByIndex(GetPointOfInterestCount() - 1);
}
#pragma once
#include "CoreMinimal.h"
#include "PointOfInterest.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(POILog, All, All)
UCLASS()
class APointOfInterest : public AActor
{
GENERATED_BODY()
public:
APointOfInterest();
};
#pragma once
#include "CoreMinimal.h"
#include "Components/SplineComponent.h"
#include "PointOfInterestManager.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(POIManagerLog, All, All);
class APointOfInterest;
class FCameraRide;
UCLASS(Blueprintable)
class APointOfInterestManager : public AActor
{
GENERATED_BODY()
public:
APointOfInterestManager();
virtual void TickActor(float DeltaTime, enum ELevelTick TickType, FActorTickFunction& ThisTickFunction) override;
UFUNCTION(CallInEditor, BlueprintCallable)
void ResetToPlayerStart();
UFUNCTION(CallInEditor, BlueprintCallable, Category="Point Of Interest Manager")
void AddPointOfInterest();
UFUNCTION(CallInEditor, BlueprintCallable, Category="Point Of Interest Manager")
void VisitNextPointOfInterest();
UFUNCTION(CallInEditor, BlueprintCallable, Category="Point Of Interest Manager")
void VisitPreviousPointOfInterest();
UFUNCTION(BlueprintCallable, Category="Point Of Interest Manager")
void VisitPointOfInterestByIndex(int index);
UFUNCTION(BlueprintCallable, Category="Point Of Interest Manager")
void VisitPointOfInterest(APointOfInterest* POI) const;
UFUNCTION(CallInEditor, BlueprintCallable, Category="Point Of Interest Manager")
void StartCameraRide();
UFUNCTION(CallInEditor, BlueprintCallable, Category="Point Of Interest Manager")
void StopCameraRide();
UFUNCTION(BlueprintCallable, Category="Point Of Interest Manager")
int GetPointOfInterestCount();
/**
* Whether the camera should progress a constant distance between ticks (true) or a variable distance based on frametimes (false).
* This should be set to true if you expect long/inconsistent frame times or for e.g. PSO gathering.
*/
UPROPERTY(EditAnywhere, Category="Point Of Interest Manager")
bool MakeCameraRideProgressionConstantBetweenTicks = true;
/**
* Only relevant when MakeCameraRideProgressionConstantBetweenTicks = true.
* The conversion rate of how many ticks the camera should update to equal the distance traveled during 1 second.
*/
UPROPERTY(EditAnywhere, Category="Point Of Interest Manager",
meta = (EditCondition = "MakeCameraRideProgressionConstantBetweenTicks"))
int CameraRideSecondsToUpdates = 60;
protected:
UPROPERTY(EditAnywhere)
TArray<APointOfInterest*> POIs;
int CurrentPOIIndex = 0;
private:
UFUNCTION(CallInEditor, BlueprintCallable, Category="Point Of Interest Manager")
void UpdateSpline();
void ProgressCameraRide();
void CameraRideEnded();
USplineComponent* SplineComponent;
UPROPERTY(EditAnywhere, meta=(UIMin = 0.0, UIMax = 500))
float CameraSpeed = 100;
bool IsRidingCamera;
float CameraRideStart, CameraRideEnd;
int DurationInUpdates, CurrentUpdate;
};
...@@ -25,7 +25,7 @@ public class RWTHVRQuickStart : ModuleRules ...@@ -25,7 +25,7 @@ public class RWTHVRQuickStart : ModuleRules
PublicDependencyModuleNames.AddRange( PublicDependencyModuleNames.AddRange(
new string[] new string[]
{ {
"Core", "Core", "Engine", "Engine",
// ... add other public dependencies that you statically link with here ... // ... add other public dependencies that you statically link with here ...
} }
); );
...@@ -37,7 +37,7 @@ public class RWTHVRQuickStart : ModuleRules ...@@ -37,7 +37,7 @@ public class RWTHVRQuickStart : ModuleRules
"CoreUObject", "CoreUObject",
"Engine", "Engine",
"Slate", "Slate",
"SlateCore", "SlateCore", "RWTHVRToolkit", "RWTHVRToolkit",
// ... add private dependencies that you statically link with here ... // ... add private dependencies that you statically link with here ...
} }
); );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment