Start of dynamic camera in C++

This commit is contained in:
Kevin Poretti 2023-01-15 22:29:36 -05:00
parent b4e7468204
commit d07a08793b
11 changed files with 206 additions and 4 deletions

View File

@ -54,6 +54,7 @@ AppliedDefaultGraphicsPerformance=Maximum
+ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPerson",NewGameName="/Script/GravityStomp")
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonGameMode",NewClassName="GravityStompGameMode")
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="GravityStompCharacter")
WorldSettingsClassName=/Script/GravityStompGame.GSWorldSettings
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
bEnablePlugin=True

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
GravityStomp/Content/Debug/Camera/TestCamera.umap (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GravityStomp/Content/Maps/Debug/Test.umap (Stored with Git LFS)

Binary file not shown.

View File

@ -0,0 +1,115 @@
// Gravity Stomp Copyright Kevin Poretti
#include "Camera/GSCameraActor.h"
// UE includes
#include "Kismet/KismetMathLibrary.h"
#include "World/GSWorldSettings.h"
AGSCameraActor::AGSCameraActor()
{
PanSpeed = 100.0f;
ZoomSpeed = 100.0f;
}
void AGSCameraActor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
FBox2D ScreenBoundingBox = GetBoundingBoxFromViewportPercentage(0);
// bounding box of what is considered the "edge" of the screen
// when characters are outside of this box the camera should pan or zoom out
FBox2D EdgeBoundingBox = GetBoundingBoxFromViewportPercentage(0.15);
// bounding box of what is considered the "center" of the screen
// when all characters are inside of this box the camera should zoom in
FBox2D CenterBoundingBox = GetBoundingBoxFromViewportPercentage(0.15);
// debug
FVector2D ScreenBoxCenter = GetBoxCenter(ScreenBoundingBox);
float ScreenHeight, ScreenWidth;
GetBoxDimensions(ScreenBoundingBox, ScreenHeight, ScreenWidth);
DrawDebugBox(GetWorld(), FVector(0.0f, ScreenBoxCenter.X, ScreenBoxCenter.Y), FVector(0.0f, ScreenWidth/2, ScreenHeight/2),
FColor::Magenta, false, -1, 0, 2.0f);
FVector CurrLocation = GetActorLocation();
float ZoomMove = ZoomDirection * ZoomSpeed * DeltaSeconds;
FVector2D PanMove = PanDirection * PanSpeed * DeltaSeconds;
FVector2D NewPan = FVector2D(CurrLocation.Y + PanMove.X, CurrLocation.Z + PanMove.Y);
NewPan = ClampCameraLocationToStageBounds(NewPan, ScreenBoundingBox);
FVector NewLocation = FVector(CurrLocation.X + ZoomMove, NewPan.X, NewPan.Y);
SetActorLocation(NewLocation);
}
FBox2D AGSCameraActor::GetBoundingBoxFromViewportPercentage(float ScreenPercentage) const
{
APlayerController* PC = GetWorld()->GetFirstPlayerController();
int32 SizeX, SizeY;
PC->GetViewportSize(SizeX, SizeY);
float MinX = ((float)SizeX) * ScreenPercentage;
float MinY = ((float)SizeY) * ScreenPercentage;
float MaxX = ((float)SizeX) * (1 - ScreenPercentage);
float MaxY = ((float)SizeY) * (1 - ScreenPercentage);
FVector TopRight = GetWorldLocationFromScreenCoords(MaxX, MinY);
FVector BottomLeft = GetWorldLocationFromScreenCoords(MinX, MaxY);
FBox2D Result;
Result.Min = FVector2D(BottomLeft.Y, BottomLeft.Z);
Result.Max = FVector2D(TopRight.Y, TopRight.Z);
return Result;
}
FVector2D AGSCameraActor::GetBoxCenter(FBox2D Box) const
{
return FVector2D((Box.Min.X + Box.Max.X) / 2.0f, (Box.Min.Y + Box.Max.Y) / 2.0f);
}
void AGSCameraActor::GetBoxDimensions(FBox2D Box, float& BoxHeight, float& BoxWidth) const
{
BoxWidth = FMath::Abs(Box.Max.X - Box.Min.X);
BoxHeight = FMath::Abs(Box.Max.Y - Box.Min.Y);
}
FVector AGSCameraActor::GetWorldLocationFromScreenCoords(float InX, float InY) const
{
APlayerController* PC = GetWorld()->GetFirstPlayerController();
FVector WorldLocation;
FVector WorldDirection;
PC->DeprojectScreenPositionToWorld(InX, InY, WorldLocation, WorldDirection);
FPlane XPlane = UKismetMathLibrary::MakePlaneFromPointAndNormal(FVector::ZeroVector, FVector::ForwardVector);
// NOTE: 10000 is a big enough number to make sure the intersection goes through the X = 0 plane
// there is probably a more elegant way to do this
float T;
FVector Result = FVector::ZeroVector;
UKismetMathLibrary::LinePlaneIntersection(WorldLocation, WorldLocation + (WorldDirection * 10000), XPlane, T, Result);
return Result;
}
FVector2D AGSCameraActor::ClampCameraLocationToStageBounds(FVector2D CameraLocation, FBox2D ScreenBox) const
{
AGSWorldSettings* WS = Cast<AGSWorldSettings>(GetWorld()->GetWorldSettings());
FBox2D StageBounds = WS->StageBounds;
float ScreenHeight, ScreenWidth;
GetBoxDimensions(ScreenBox, ScreenHeight, ScreenWidth);
float HalfHeight = ScreenHeight / 2;
float HalfWidth = ScreenWidth / 2;
float MinStageX = StageBounds.Min.X + HalfWidth;
float MinStageY = StageBounds.Min.Y + HalfHeight;
float MaxStageX = StageBounds.Max.X - HalfWidth;
float MaxStageY = StageBounds.Max.Y - HalfHeight;
float FinalX = FMath::Clamp(CameraLocation.X, MinStageX, MaxStageX);
float FinalY = FMath::Clamp(CameraLocation.Y, MinStageY, MaxStageY);
return FVector2D(FinalX, FinalY);
}

View File

@ -0,0 +1,45 @@
// Gravity Stomp Copyright Kevin Poretti
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraActor.h"
#include "GSCameraActor.generated.h"
/**
*
*/
UCLASS(showcategories=(Input))
class GRAVITYSTOMPGAME_API AGSCameraActor : public ACameraActor
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Camera Settings")
float PanSpeed;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Camera Settings")
float ZoomSpeed;
UPROPERTY(BlueprintReadWrite)
FVector2D PanDirection;
UPROPERTY(BlueprintReadWrite)
float ZoomDirection;
AGSCameraActor();
protected:
virtual void Tick(float DeltaSeconds) override;
private:
FBox2D GetBoundingBoxFromViewportPercentage(float ScreenPercentage) const;
FVector2D GetBoxCenter(FBox2D Box) const;
void GetBoxDimensions(FBox2D Box, float& BoxHeight, float& BoxWidth) const;
FVector GetWorldLocationFromScreenCoords(float InX, float InY) const;
FVector2D ClampCameraLocationToStageBounds(FVector2D CameraLocation, FBox2D ScreenBox) const;
};

View File

@ -22,7 +22,7 @@ public class GravityStompGame : ModuleRules
"CoreUObject",
"Engine",
"InputCore",
"EnhancedInput"
"EnhancedInput",
}
);
}

View File

@ -0,0 +1,10 @@
// Gravity Stomp Copyright Kevin Poretti
#include "World/GSWorldSettings.h"
AGSWorldSettings::AGSWorldSettings()
{
StageBounds.Min = FVector2D(-2000.0f, 0.0f);
StageBounds.Max = FVector2D(2000.0f, 2250.0f);
}

View File

@ -0,0 +1,22 @@
// Gravity Stomp Copyright Kevin Poretti
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/WorldSettings.h"
#include "GSWorldSettings.generated.h"
/**
*
*/
UCLASS()
class GRAVITYSTOMPGAME_API AGSWorldSettings : public AWorldSettings
{
GENERATED_BODY()
public:
AGSWorldSettings();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Gravity Stomp Settings")
FBox2D StageBounds;
};