diff --git a/Content/FirstPerson/Blueprints/BP_FirstPersonCharacter.uasset b/Content/FirstPerson/Blueprints/BP_FirstPersonCharacter.uasset index 323855d..0e541cc 100644 --- a/Content/FirstPerson/Blueprints/BP_FirstPersonCharacter.uasset +++ b/Content/FirstPerson/Blueprints/BP_FirstPersonCharacter.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:143c7d036d0cfe8c8519a3eb1a994db945f239f9f1a4fbfdc70e2f13fdf4579c -size 25994 +oid sha256:d633171bc248bf40c6c0c41ae2021744318a13363cb70ae35ab5b7c22e74d3e0 +size 51739 diff --git a/Content/FirstPerson/Blueprints/CameraShakes/CSB_Floating.uasset b/Content/FirstPerson/Blueprints/CameraShakes/CSB_Floating.uasset new file mode 100644 index 0000000..abd1527 --- /dev/null +++ b/Content/FirstPerson/Blueprints/CameraShakes/CSB_Floating.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c515fcae3eea62bfaec9b39e837b0caea30f710fc4de7b7782620738c6b5206 +size 5685 diff --git a/Content/FirstPerson/Blueprints/CameraShakes/CSB_Idling.uasset b/Content/FirstPerson/Blueprints/CameraShakes/CSB_Idling.uasset new file mode 100644 index 0000000..7ba2cfa --- /dev/null +++ b/Content/FirstPerson/Blueprints/CameraShakes/CSB_Idling.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b4f1a5d0f57ae48f0d758735d9cf36a488e6d643c96e439a95b4d124d346123 +size 6354 diff --git a/Content/FirstPerson/Blueprints/CameraShakes/CSB_Running.uasset b/Content/FirstPerson/Blueprints/CameraShakes/CSB_Running.uasset new file mode 100644 index 0000000..5c184f8 --- /dev/null +++ b/Content/FirstPerson/Blueprints/CameraShakes/CSB_Running.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2390d73eb7357ed279c7f29d526d236ad46fa6879a9b8f6400bd47fbce68d981 +size 7850 diff --git a/Content/FirstPerson/Blueprints/CameraShakes/CSB_Walking.uasset b/Content/FirstPerson/Blueprints/CameraShakes/CSB_Walking.uasset new file mode 100644 index 0000000..ef6abff --- /dev/null +++ b/Content/FirstPerson/Blueprints/CameraShakes/CSB_Walking.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ad3788db8a2b83fb9f92b5480fb4e70e902c73e14597cc6ad2097b06f9a63c60 +size 7354 diff --git a/Content/FirstPerson/HUD/WBP_DashesRemaining.uasset b/Content/FirstPerson/HUD/WBP_DashesRemaining.uasset new file mode 100644 index 0000000..2be9372 --- /dev/null +++ b/Content/FirstPerson/HUD/WBP_DashesRemaining.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:573b8d01b4f498fd9134b0f3349203a101786474ad726e22bde97fb6d0ccbec4 +size 84134 diff --git a/Content/FirstPerson/Input/Actions/Dashes/IA_HORIZONTAL_DASH.uasset b/Content/FirstPerson/Input/Actions/Dashes/IA_HORIZONTAL_DASH.uasset new file mode 100644 index 0000000..da3a305 --- /dev/null +++ b/Content/FirstPerson/Input/Actions/Dashes/IA_HORIZONTAL_DASH.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3d8378afb54f427030ee7a8c9d69412453ba635e35597130542e85d745eef3a3 +size 1457 diff --git a/Content/FirstPerson/Input/Actions/Dashes/IA_VERTICAL_DASH.uasset b/Content/FirstPerson/Input/Actions/Dashes/IA_VERTICAL_DASH.uasset new file mode 100644 index 0000000..4a1f2d7 --- /dev/null +++ b/Content/FirstPerson/Input/Actions/Dashes/IA_VERTICAL_DASH.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49a62c85ac85b21b56c637f067293e22be55a2941091a4c1c34d89ee3091a8c7 +size 1447 diff --git a/Content/FirstPerson/Input/Actions/IA_Sprint.uasset b/Content/FirstPerson/Input/Actions/IA_Sprint.uasset new file mode 100644 index 0000000..9422fa8 --- /dev/null +++ b/Content/FirstPerson/Input/Actions/IA_Sprint.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:45227903b4baafd2b941f14934e9149f66fcebeb82441e9f3f002441cd62390a +size 1398 diff --git a/Content/FirstPerson/Input/IMC_Default.uasset b/Content/FirstPerson/Input/IMC_Default.uasset index 959253f..f27d268 100644 --- a/Content/FirstPerson/Input/IMC_Default.uasset +++ b/Content/FirstPerson/Input/IMC_Default.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e165f1846da6b13a3c325bcf7dabfc80117868326e594aa44d03963900ddacac -size 13199 +oid sha256:09b851b46656e67d2ccfcaafd51980be4f75441d715cf17bd5405a1a82a5892d +size 17565 diff --git a/Content/FirstPersonArms/Animations/FirstPerson_AnimBP.uasset b/Content/FirstPersonArms/Animations/FirstPerson_AnimBP.uasset index d2308a5..2585f14 100644 --- a/Content/FirstPersonArms/Animations/FirstPerson_AnimBP.uasset +++ b/Content/FirstPersonArms/Animations/FirstPerson_AnimBP.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb78c38a5f009dec1ebb0be6f19030f3b7e2dc6942b51626b1858f3ac044c0cd -size 445166 +oid sha256:ebd719725542c4751e05d25ef0d1071aebfe484c33a8d4ac25c5587cd9558a89 +size 439229 diff --git a/Source/Monolith/MonolithCharacter.cpp b/Source/Monolith/MonolithCharacter.cpp index 2861ea2..d60a6b6 100644 --- a/Source/Monolith/MonolithCharacter.cpp +++ b/Source/Monolith/MonolithCharacter.cpp @@ -1,46 +1,63 @@ // Copyright Epic Games, Inc. All Rights Reserved. #include "MonolithCharacter.h" + #include "Animation/AnimInstance.h" -#include "PilotCamera.h" #include "Components/CapsuleComponent.h" #include "Components/SkeletalMeshComponent.h" +#include "Engine/LocalPlayer.h" +#include "GameFramework/CharacterMovementComponent.h" + #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" #include "InputActionValue.h" -#include "Engine/LocalPlayer.h" DEFINE_LOG_CATEGORY(LogTemplateCharacter); ////////////////////////////////////////////////////////////////////////// // AMonolithCharacter +void AMonolithCharacter::StartRechargingDash() +{ + if (DashRechargeHandle.IsValid()) return; + GetWorld()->GetTimerManager().SetTimer(DashRechargeHandle, this + , &AMonolithCharacter::DashRecharged, DashRechargeTime); +} + +void AMonolithCharacter::DashRecharged() +{ + DashesRemaining++; + UpdateDashUI(DashesRemaining); + DashRechargeHandle.Invalidate(); + if (DashesRemaining < 4) + { + StartRechargingDash(); + } +} + AMonolithCharacter::AMonolithCharacter() { // Set size for collision capsule GetCapsuleComponent()->InitCapsuleSize(55.f, 96.0f); - - // Create a CameraComponent - FirstPersonCameraComponent = CreateDefaultSubobject(TEXT("FirstPersonCamera")); - FirstPersonCameraComponent->SetupAttachment(GetCapsuleComponent()); - FirstPersonCameraComponent->SetRelativeLocation(FVector(-10.f, 0.f, 60.f)); // Position the camera - FirstPersonCameraComponent->bUsePawnControlRotation = true; - - // Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn) - Mesh1P = CreateDefaultSubobject(TEXT("CharacterMesh1P")); - Mesh1P->SetOnlyOwnerSee(true); - Mesh1P->SetupAttachment(FirstPersonCameraComponent); - Mesh1P->bCastDynamicShadow = false; - Mesh1P->CastShadow = false; - //Mesh1P->SetRelativeRotation(FRotator(0.9f, -19.19f, 5.2f)); - Mesh1P->SetRelativeLocation(FVector(-30.f, 0.f, -150.f)); - } void AMonolithCharacter::BeginPlay() { // Call the base class Super::BeginPlay(); + + Mesh1P = Cast(GetComponentByClass(USkeletalMeshComponent::StaticClass())); + CharMove = Cast(GetComponentByClass(UCharacterMovementComponent::StaticClass())); + if (CharMove) WalkSpeed = CharMove->MaxWalkSpeed; +} + +void AMonolithCharacter::Tick(float DeltaSeconds) +{ + Super::Tick(DeltaSeconds); + if (CharMove == nullptr) return; + CharMove->IsFalling() ? MoveState.Remove(GROUNDED) : MoveState.Add(GROUNDED); + MoveState.VelocityMag = CharMove->Velocity.Length(); + MoveState.VelocityMag < VelocityTolerance ? MoveState.Add(STILL) : MoveState.Remove(STILL); } //////////////////////////////////////////////////////////////////////////// Input @@ -56,6 +73,15 @@ void AMonolithCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputC // Moving EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMonolithCharacter::Move); + EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Completed, this, &AMonolithCharacter::StopMove); + + // Sprinting + EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Triggered, this, &AMonolithCharacter::Sprint); + EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Completed, this, &AMonolithCharacter::StopSprint); + + // Dashing + EnhancedInputComponent->BindAction(HorDashAction, ETriggerEvent::Triggered, this, &AMonolithCharacter::HorizontalDash); + EnhancedInputComponent->BindAction(VerDashAction, ETriggerEvent::Triggered, this, &AMonolithCharacter::VerticalDash); // Looking EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AMonolithCharacter::Look); @@ -66,21 +92,112 @@ void AMonolithCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputC } } +static void UpdateMoveState(FMoveState& MoveState, int Forwards, int Sideways) +{ + if (Sideways && !Forwards) + { // STRAFING + if (Sideways > 0) + { + MoveState.Add(STRAFE_R); + MoveState.Remove(STRAFE_L); + } + else + { + MoveState.Add(STRAFE_L); + MoveState.Remove(STRAFE_R); + } + MoveState.Remove(FORWARD); + } + else if (Forwards > 0) + { // GOING ROUGHLY FORWARD + MoveState.Add(FORWARD); + MoveState.Remove(STRAFE_L); + MoveState.Remove(STRAFE_R); + } + else + { + MoveState.Remove(FORWARD); + MoveState.Remove(STRAFE_L); + MoveState.Remove(STRAFE_R); + } +} void AMonolithCharacter::Move(const FInputActionValue& Value) { // input is a Vector2D - FVector2D MovementVector = Value.Get(); + MovementVector = Value.Get(); if (Controller != nullptr) { // add movement AddMovementInput(GetActorForwardVector(), MovementVector.Y); AddMovementInput(GetActorRightVector(), MovementVector.X); - UE_LOG(LogTemp, Warning, TEXT("X: %f, Y: %f"), (float)MovementVector.X, (float)MovementVector.Y); + UpdateMoveState(MoveState, MovementVector.Y, MovementVector.X); } } +void AMonolithCharacter::StopMove() +{ + MoveState.Remove(STRAFE_L); + MoveState.Remove(STRAFE_R); + MoveState.Remove(FORWARD); + MoveState.Remove(SPRINT); +} + +void AMonolithCharacter::Sprint(const FInputActionValue& Value) +{ + if (CharMove == nullptr || MoveState.Is(SPRINT)) return; + + if (!MoveState.Is(FORWARD) + || !MoveState.Is(GROUNDED)) + { + StopSprint(); + } + else + { + MoveState.Add(SPRINT); + CharMove->MaxWalkSpeed = SprintSpeed; + } +} + +void AMonolithCharacter::StopSprint() +{ + MoveState.Remove(SPRINT); + CharMove->MaxWalkSpeed = WalkSpeed; +} + +void AMonolithCharacter::HorizontalDash(const FInputActionValue& Value) +{ + if (DashesRemaining <= 0) return; + DashesRemaining--; + UpdateDashUI(DashesRemaining); + FVector Impulse; + if (MovementVector.Y) + { + Impulse = MovementVector.Y > 0 + ? GetActorForwardVector() : -GetActorForwardVector(); + } + else + { + Impulse = MovementVector.X > 0 + ? GetActorRightVector() : -GetActorRightVector(); + } + Impulse *= DashImpulse; + Impulse.Z += DashImpulse * 0.25f; + CharMove->AddImpulse(Impulse, true); + StartRechargingDash(); +} + +void AMonolithCharacter::VerticalDash(const FInputActionValue& Value) +{ + if (DashesRemaining <= 0) return; + DashesRemaining--; + UpdateDashUI(DashesRemaining); + FVector Impulse(0, 0, DashImpulse * 0.55f); + CharMove->AddImpulse(Impulse, true); + StartRechargingDash(); +} + void AMonolithCharacter::Look(const FInputActionValue& Value) { // input is a Vector2D @@ -92,4 +209,4 @@ void AMonolithCharacter::Look(const FInputActionValue& Value) AddControllerYawInput(LookAxisVector.X); AddControllerPitchInput(LookAxisVector.Y); } -} \ No newline at end of file +} diff --git a/Source/Monolith/MonolithCharacter.h b/Source/Monolith/MonolithCharacter.h index da1d870..b7a5d0d 100644 --- a/Source/Monolith/MonolithCharacter.h +++ b/Source/Monolith/MonolithCharacter.h @@ -5,12 +5,15 @@ #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "Logging/LogMacros.h" +#include "MoveState.h" +#include "PilotCamera.h" +#include "PilotCameraShake.h" #include "MonolithCharacter.generated.h" -class UInputComponent; +class UCharacterMovementComponent; class USkeletalMeshComponent; -class UPilotCamera; class UInputAction; +class UInputComponent; class UInputMappingContext; struct FInputActionValue; @@ -21,14 +24,9 @@ class AMonolithCharacter : public ACharacter { GENERATED_BODY() - /** Pawn mesh: 1st person view (arms; seen only by self) */ - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Mesh, meta = (AllowPrivateAccess = "true")) - USkeletalMeshComponent* Mesh1P; - - /** First person camera */ - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) - UPilotCamera* FirstPersonCameraComponent; - + friend UPilotCamera; + friend UPilotCameraShake; + /** Jump Input Action */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) UInputAction* JumpAction; @@ -37,34 +35,82 @@ class AMonolithCharacter : public ACharacter UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) UInputAction* MoveAction; - int fortnite = 69; + /** Sprint Input Action */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) + UInputAction* SprintAction; + + /** Horizontal Dash Input Action */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) + UInputAction* HorDashAction; + + /** Vertical Dash Input Action */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) + UInputAction* VerDashAction; + + UPROPERTY(EditDefaultsOnly, Category=Input, meta=(AllowPrivateAccess = "true")) + float SprintSpeed = 750.f; + float WalkSpeed = 600.f; + + // Velocity Below this Value will be Ignored for Camera Effects + UPROPERTY(EditAnywhere, Category = "MoveState", meta=(AllowPrivateAccess = "true")) + float VelocityTolerance = 300.f; + + // Amount of impulse to add when dashing + UPROPERTY(EditAnywhere, Category = "MoveState", meta=(AllowPrivateAccess = "true")) + float DashImpulse = 600.f; -public: - AMonolithCharacter(); + USkeletalMeshComponent* Mesh1P; + UCharacterMovementComponent* CharMove; + + FMoveState MoveState; + + FVector2D MovementVector; protected: - virtual void BeginPlay(); + void BeginPlay(); + void Tick(float DeltaSeconds) override; -public: - - /** Look Input Action */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true")) - class UInputAction* LookAction; - -protected: /** Called for movement input */ void Move(const FInputActionValue& Value); + void StopMove(); + + /** Called for SPRINT input */ + void Sprint(const FInputActionValue& Value); + void StopSprint(); + + /** Called for Dashing inputs */ + void HorizontalDash(const FInputActionValue& Value); + void VerticalDash(const FInputActionValue& Value); /** Called for looking input */ void Look(const FInputActionValue& Value); - -protected: + // APawn interface virtual void SetupPlayerInputComponent(UInputComponent* InputComponent) override; // End of APawn interface + // Time to recharge 1 dash + UPROPERTY(EditDefaultsOnly, Category = "MoveState", meta = (AllowPrivateAccess = "true")) + float DashRechargeTime = 2.5f; + FTimerHandle DashRechargeHandle; + int DashesRemaining = 4; + void StartRechargingDash(); + void DashRecharged(); + UFUNCTION(BlueprintImplementableEvent) + void UpdateDashUI(int dashesRemaining); + public: - /** Returns Mesh1P subobject **/ - USkeletalMeshComponent* GetMesh1P() const { return Mesh1P; } + AMonolithCharacter(); + + /** Look Input Action */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true")) + class UInputAction* LookAction; + + USkeletalMeshComponent* GetMesh1P() + { + if (Mesh1P) return Mesh1P; + Mesh1P = Cast(GetComponentByClass(USkeletalMeshComponent::StaticClass())); + return Mesh1P; + } }; diff --git a/Source/Monolith/MoveState.h b/Source/Monolith/MoveState.h new file mode 100644 index 0000000..d995258 --- /dev/null +++ b/Source/Monolith/MoveState.h @@ -0,0 +1,33 @@ +#pragma once + +using State = unsigned short; +#define STRAFE_L 0x1 +#define STRAFE_R 0x2 +#define SPRINT 0x4 +#define GROUNDED 0x8 +#define FORWARD 0x10 +#define STILL 0x20 + + +class FMoveState +{ + State MoveState = 0; + +public: + bool Is(State state) const + { + return MoveState & state; + } + + void Add(State state) + { + MoveState += Is(state) ? 0 : state; + } + + void Remove(State state) + { + MoveState -= Is(state) ? state : 0; + } + + double VelocityMag = 0; +}; diff --git a/Source/Monolith/PilotCamera.cpp b/Source/Monolith/PilotCamera.cpp index 50b2375..8a4d184 100644 --- a/Source/Monolith/PilotCamera.cpp +++ b/Source/Monolith/PilotCamera.cpp @@ -1,23 +1,82 @@ // Fill out your copyright notice in the Description page of Project Settings. - #include "PilotCamera.h" #include "MonolithPlayerController.h" #include "MonolithCharacter.h" -#include "GameFramework/CharacterMovementComponent.h" +#include "MoveState.h" void UPilotCamera::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - if (m_Movement == nullptr) - { - AMonolithCharacter* PlayerChar = Cast + + if (TickType == LEVELTICK_ViewportsOnly + || (!isMoveStateSet() && !TrySetMoveState())) return; + + // TODO - Set FOV based on Velocity mag + UpdateFOV(DeltaTime); + + // TODO - Add Camera Roll if Strafing + UpdateRoll(DeltaTime); + // if (MoveState->Is(STRAFE_L)) UE_LOG(LogTemp, Warning, TEXT("Strafing Left")); + // if (MoveState->Is(STRAFE_R)) UE_LOG(LogTemp, Warning, TEXT("Strafing Right")); + // if (MoveState->Is(SPRINT)) UE_LOG(LogTemp, Warning, TEXT("Sprinting")); + // if (MoveState->Is(GROUNDED)) UE_LOG(LogTemp, Warning, TEXT("On the floor")); + // if (MoveState->Is(FORWARD)) UE_LOG(LogTemp, Warning, TEXT("Going FORWARD")); +} + +bool UPilotCamera::TrySetMoveState() +{ + AMonolithCharacter* PlayerChar = Cast ( Cast(GetWorld()->GetFirstPlayerController())->GetPawn() ); - if (PlayerChar == nullptr) return; - m_Movement = PlayerChar->GetComponentByClass(); - if (m_Movement == nullptr) return; - } - UE_LOG(LogTemp, Warning, TEXT("Acc: %f, Vel: %f"), m_Movement->GetCurrentAcceleration().X, m_Movement->Velocity.X); + if ( PlayerChar == nullptr) return false; + MoveState = &PlayerChar->MoveState; + return MoveState != nullptr; } + +void UPilotCamera::UpdateFOV(float DeltaTime) +{ + const float targetFOV = GetTargetFOV(); + if (FieldOfView == targetFOV) return; + + float linearModifier = 1 - (FMath::Abs(targetFOV - FieldOfView)) / targetFOV; + float rateOfChange = RateOfChange * DeltaTime * linearModifier; + bool increasing = targetFOV > FieldOfView; + rateOfChange *= increasing ? 1 : -1; + + float newFOV = FieldOfView + rateOfChange; + if ((increasing && newFOV > targetFOV) || (!increasing && newFOV < targetFOV)) + { + newFOV = targetFOV; + } + SetFieldOfView(newFOV); +} + +void UPilotCamera::UpdateRoll(float DeltaTime) +{ + FRotator rot = GetRelativeRotation(); + if (MoveState->Is(STRAFE_R)) + { + TargetRoll = MaxStrafeRoll; + } + else if (MoveState->Is(STRAFE_L)) + { + TargetRoll = -MaxStrafeRoll; + } + else + { + TargetRoll = 0; + } + float rateOfChange = RollRateOfChange * DeltaTime; + bool increasing = TargetRoll > rot.Roll; + rateOfChange *= increasing ? 1 : -1; + rot.Roll += rateOfChange; + if ((increasing && rot.Roll > TargetRoll) || (!increasing && rot.Roll < TargetRoll)) + { + rot.Roll = TargetRoll; + } + + SetRelativeRotation(rot); +} + diff --git a/Source/Monolith/PilotCamera.h b/Source/Monolith/PilotCamera.h index f50fb86..91307dd 100644 --- a/Source/Monolith/PilotCamera.h +++ b/Source/Monolith/PilotCamera.h @@ -3,19 +3,59 @@ #pragma once #include "CoreMinimal.h" +#include "MoveState.h" #include "Camera/CameraComponent.h" #include "PilotCamera.generated.h" -class UCharacterMovementComponent; +class FMoveState; -UCLASS() + +UCLASS(Blueprintable, ClassGroup=Camera, meta=(BlueprintSpawnableComponent)) class MONOLITH_API UPilotCamera : public UCameraComponent { GENERATED_BODY() - -private: - void TickComponent(float DeltaTime - , ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction); + using FOVs = std::tuple; + #define ARE(Stand, Walk, Sprint) std::make_tuple(Stand, Walk, Sprint) - UCharacterMovementComponent* m_Movement; + void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction); + inline bool isMoveStateSet() const; + bool TrySetMoveState(); + + // FOV + FOVs TargetFOVs = ARE(87.f, 92.f, 100.f); + const float RateOfChange = 30; + float GetTargetFOV() const; + void UpdateFOV(float DeltaTime); + + // Roll + float TargetRoll = 0; + // Max amount of roll applied when strafing + UPROPERTY(EditDefaultsOnly, Category = "Move State", meta = (AllowPrivateAccess = "true")) + float MaxStrafeRoll = 3; + // Amount of roll applied per second + UPROPERTY(EditDefaultsOnly, Category = "Move State", meta = (AllowPrivateAccess = "true")) + float RollRateOfChange = 15; + void UpdateRoll(float DeltaTime); + + // TODO - Implement these + void ApplyImpulseFOV(); + void ImpactCameraShake(); + + FMoveState* MoveState; }; + +inline float UPilotCamera::GetTargetFOV() const +{ + auto[stand, walk, sprint] = TargetFOVs; + if (MoveState->Is(SPRINT)) return sprint; + if (!MoveState->Is(STILL) + && !MoveState->Is(STRAFE_R) + && !MoveState->Is(STRAFE_L)) return walk; + return stand; +} + +inline bool UPilotCamera::isMoveStateSet() const +{ + return MoveState != nullptr; +} + diff --git a/Source/Monolith/PilotCameraShake.cpp b/Source/Monolith/PilotCameraShake.cpp new file mode 100644 index 0000000..4033358 --- /dev/null +++ b/Source/Monolith/PilotCameraShake.cpp @@ -0,0 +1,62 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "PilotCameraShake.h" +#include "MonolithCharacter.h" +#include "MonolithPlayerController.h" +#include "MoveState.h" + +void UPilotCameraShake::BeginPlay() +{ + Super::BeginPlay(); + // For some reason camera shakes dont override tick :(( + GetWorld()->GetTimerManager().SetTimer(TickHandle, this + , &UPilotCameraShake::UpdateCameraShake, 0.25f, true); +} + +bool UPilotCameraShake::TrySetMoveState() +{ + AMonolithCharacter* PlayerChar = Cast + ( + Cast(GetWorld()->GetFirstPlayerController())->GetPawn() + ); + if ( PlayerChar == nullptr) return false; + MoveState = &PlayerChar->MoveState; + return MoveState != nullptr; +} + +void UPilotCameraShake::UpdateCameraShake() +{ + if (CantUpdate()) return; + + if (!MoveState->Is(GROUNDED)) + { + if (CurrentState == Floating) return; + CurrentState = Floating; + SetCameraShakeBase(FloatingShake); + } + else if (MoveState->Is(SPRINT)) + { + if (CurrentState == Running) return; + CurrentState = Running; + SetCameraShakeBase(RunningShake); + } + else if (MoveState->Is(STILL)) + { + if (CurrentState == Idling) return; + CurrentState = Idling; + SetCameraShakeBase(IdleShake); + } + else + { + if (CurrentState == Walking) return; + CurrentState = Walking; + SetCameraShakeBase(WalkingShake); + } +} + +void UPilotCameraShake::SetCameraShakeBase(TSubclassOf ShakeBase) +{ + StopAllCameraShakes(); + StartCameraShake(ShakeBase); +} diff --git a/Source/Monolith/PilotCameraShake.h b/Source/Monolith/PilotCameraShake.h new file mode 100644 index 0000000..ae6dfd2 --- /dev/null +++ b/Source/Monolith/PilotCameraShake.h @@ -0,0 +1,55 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Camera/CameraShakeSourceComponent.h" +#include "PilotCameraShake.generated.h" + +class FMoveState; + + +UCLASS(Blueprintable, ClassGroup=Camera, meta=(BlueprintSpawnableComponent)) +class MONOLITH_API UPilotCameraShake : public UCameraShakeSourceComponent +{ + GENERATED_BODY() + + enum EState{Idling, Walking, Running, Floating}; + + void BeginPlay() override; + + bool CantUpdate(); + bool isMoveStateSet() const; + bool TrySetMoveState(); + UFUNCTION(BlueprintCallable) + void UpdateCameraShake(); + void SetCameraShakeBase(TSubclassOf ShakeBase); + + FTimerHandle TickHandle; + + FMoveState* MoveState; + EState CurrentState = Idling; + + UPROPERTY(EditDefaultsOnly, Category = "Cam Shake", meta=(AllowPrivateAccess = "true")) + TSubclassOf RunningShake; + + UPROPERTY(EditDefaultsOnly, Category = "Cam Shake", meta=(AllowPrivateAccess = "true")) + TSubclassOf WalkingShake; + + UPROPERTY(EditDefaultsOnly, Category = "Cam Shake", meta=(AllowPrivateAccess = "true")) + TSubclassOf FloatingShake; + + UPROPERTY(EditDefaultsOnly, Category = "Cam Shake", meta=(AllowPrivateAccess = "true")) + TSubclassOf IdleShake; +}; + +inline bool UPilotCameraShake::CantUpdate() +{ + return !isMoveStateSet() && !TrySetMoveState(); +} + + +inline bool UPilotCameraShake::isMoveStateSet() const +{ + return MoveState != nullptr; +} \ No newline at end of file