Skip to content
Snippets Groups Projects
Select Git revision
  • d5f20d5b123d4919cf4bde5814fcfe537fbef0f0
  • 5.4 default protected
  • feature/radialPOInav
3 results

PointOfInterestManager.cpp

Blame
  • PointOfInterestManager.cpp 4.72 KiB
    #include "PointOfInterestManager.h"
    
    #include "PointOfInterest.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::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;
    
    	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;
    	UE_LOGFMT(POIManagerLog, VeryVerbose, "");
    
    	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 (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);
    }