Mech-Shooter / GSCharacterMovementComponent.h
GSCharacterMovementComponent.h
Raw
// Copyright 2020 Dan Kestranek.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameplayTagContainer.h"
#include "Heroes/EWallRunSide.h"
#include "GSCharacterMovementComponent.generated.h"



/**
 * 
 */
UCLASS()
class GASSHOOTER_API UGSCharacterMovementComponent : public UCharacterMovementComponent
{
	GENERATED_BODY()
	
	class FGSSavedMove : public FSavedMove_Character
	{
	public:

		typedef FSavedMove_Character Super;

		///@brief Resets all saved variables.
		virtual void Clear() override;

		///@brief Store input commands in the compressed flags.
		virtual uint8 GetCompressedFlags() const override;

		///@brief This is used to check whether or not two moves can be combined into one.
		///Basically you just check to make sure that the saved variables are the same.
		virtual bool CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* Character, float MaxDelta) const override;

		///@brief Sets up the move before sending it to the server. 
		virtual void SetMoveFor(ACharacter* Character, float InDeltaTime, FVector const& NewAccel, class FNetworkPredictionData_Client_Character& ClientData) override;
		///@brief Sets variables on character movement component before making a predictive correction.
		virtual void PrepMoveFor(class ACharacter* Character) override;

		// Boost Vector
		FVector SavedMoveDirection;

		// Sprint
		uint8 SavedRequestToStartSprinting : 1;

		// Wall Run
		uint8 SavedRequestToStartWallRun : 1;

		// Ski
		uint8 SavedRequestToStartSkiing : 1;

		// Boost
		uint8 SavedRequestToStartBoost : 1;

		// SpearHook
		uint8 SavedRequestToStartSpearHook : 1;

		// Aim Down Sights
		uint8 SavedRequestToStartADS : 1;
	};

	class FGSNetworkPredictionData_Client : public FNetworkPredictionData_Client_Character
	{
	public:
		FGSNetworkPredictionData_Client(const UCharacterMovementComponent& ClientMovement);

		typedef FNetworkPredictionData_Client_Character Super;

		///@brief Allocates a new copy of our custom saved move
		virtual FSavedMovePtr AllocateNewMove() override;
	};

#pragma region Overrides
protected:
	virtual void BeginPlay() override;
	virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;

public:
	virtual float GetMaxSpeed() const override;
	virtual void UpdateFromCompressedFlags(uint8 Flags) override;
	virtual class FNetworkPredictionData_Client* GetPredictionData_Client() const override;
	virtual void OnMovementModeChanged(EMovementMode PreviousMovementMode, uint8 PreviousCustomMode) override;
	virtual void PhysCustom(float deltaTime, int32 Iterations) override;
	void PhysWallRunning(float deltaTime, int32 Iterations);
	void PhysSkating(float deltaTime, int32 Iterations);
	void PhysSpearHooking(float deltaTime, int32 Iterations);
	// Use like Tick event
	virtual void OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity) override;

#pragma endregion 

#pragma region Compressed Flags
	uint8 RequestToStartSprinting : 1;
	uint8 RequestToStartWallRun : 1;
	uint8 RequestToStartSkiing : 1;
	// Boost uses RPC 
	uint8 RequestToStartBoost : 1;
	uint8 SavedRequestToStartBoost : 1;
	uint8 RequestToStartSpearHook : 1;
	uint8 RequestToStartADS : 1;
#pragma endregion

#pragma region Defaults
public:
	UGSCharacterMovementComponent();

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speed")
	float SprintSpeedMultiplier;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speed")
	float ADSSpeedMultiplier;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Speed")
	float KnockedDownSpeedMultiplier;
	
	// The amount of vertical room between the two line traces when checking if the character is still on the wall
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "My Character Movement|Wall Running", Meta = (AllowPrivateAccess = "true"))
	float LineTraceVerticalTolerance = 50.0f;
	
	// The player's velocity while wall running
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "My Character Movement|Wall Running", Meta = (AllowPrivateAccess = "true"))
	float WallRunSpeed = 625.0f;

	/* 
	 *		SKATING
	 */
	/// Movement parameters
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Skating Parameters")
	float RunSpeed = 1280.f; // cm/s
	
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Skating Parameters")
	float MaxAccelAir = 1280.f; // cm/s^2

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Skating Parameters")
	float MaxAccelGround = 5000.f; // cm/s^2
	
#pragma endregion
	

	FGameplayTag KnockedDownTag;
	FGameplayTag InteractingTag;
	FGameplayTag InteractingRemovalTag;

	

	// Sprint
	UFUNCTION(BlueprintCallable, Category = "Sprint")
	void StartSprinting();
	UFUNCTION(BlueprintCallable, Category = "Sprint")
	void StopSprinting();

	// Wall Run
	UFUNCTION(BlueprintCallable, Category = "Wall Run")
	void StartWallRun();
	UFUNCTION(BlueprintCallable, Category = "Wall Run")
	void StopWallRun();

	// Ski
	UFUNCTION(BlueprintCallable, Category = "Ski")
	void StartSkiing();
	UFUNCTION(BlueprintCallable, Category = "Ski")
	void StopSkiing();
	
	// Boost
	UFUNCTION(BlueprintCallable, Category = "Boost")
	void StartBoost();
	UFUNCTION(BlueprintCallable, Category = "Boost")
	void StopBoost();

	// Boost
	UFUNCTION(BlueprintCallable, Category = "Spear Hook")
	void StartSpearHook();
	UFUNCTION(BlueprintCallable, Category = "Spear Hook")
	void StopSpearHook();
	
	// Aim Down Sights
	UFUNCTION(BlueprintCallable, Category = "Aim Down Sights")
	void StartAimDownSights();
	UFUNCTION(BlueprintCallable, Category = "Aim Down Sights")
	void StopAimDownSights();

#pragma region Wall Running Functions
	// Requests that the character begins wall running. Will return false if the required keys are not being pressed
	UFUNCTION(BlueprintCallable, Category = "Custom Character Movement")
	bool BeginWallRun();
	// Ends the character's wall run
	UFUNCTION(BlueprintCallable, Category = "Custom Character Movement")
	void EndWallRun();
	// Returns true if the required wall run keys are currently down
	bool IsNextToWall(float vertical_tolerance = 0.0f);
	// Finds the wall run direction and side based on the specified surface normal
	void FindWallRunDirectionAndSide(const FVector& surface_normal, FVector& direction, EWallRunSide& side) const;
	// Helper function that returns true if the specified surface normal can be wall ran on
	bool CanSurfaceBeWallRan(const FVector& surface_normal) const;
	// Returns true if the movement mode is custom and matches the provided custom movement mode
	bool IsCustomMovementMode(uint8 custom_movement_mode) const;
	
private:
	// Called when the owning actor hits something (to begin the wall run)
	UFUNCTION()
	void OnActorHit(AActor* SelfActor, AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit);
#pragma endregion

#pragma region Skiing Functions
	bool BeginSki();
	void EndSki();
private:
	/**
	   * Calculate horizontal velocity to add using quake algorithm that allows strafe-jumping
	   * @param deltaTime - timeframe to simulate over
	   * @return The calculated velocity that should be added to the total velocity for Q3 movement
	   */
	FVector GetQ3HorizontalAddVelocity(float deltaTime);

	/**
	 * Move the updated component using Velocity and deltatime. Collisions cancel all velocity normal to the hit.
	 */
	void RepositionUsingVelocity(float deltaTime, int32 Iterations);
	
	/**
	 * Apply ground friction if on the ground.
	 */
	void ApplyGroundFriction(float deltaTime);

	/**
	   * Apply gravity if updated component is not on the floor.
	   */
	void ApplyGravityToVelocity(float deltaTime);

	/**
	  * Will change vertical velocity to jumping velocity if the player is pressing jump and the character is on the floor
	  */
	void ApplyJumpStateToVelocity();
#pragma endregion

#pragma region Boost Functions
	void BeginBoost();
	UFUNCTION(Unreliable, Server, WithValidation)
	void ServerSetMoveDirection(const FVector MoveDir);
#pragma endregion

#pragma region Spear Hook Functions
	// Passed hit result from weapon ability BP
	UFUNCTION(BlueprintCallable, Category = "Custom Character Movement | Spear Hook")
	void BeginSpearHook(FHitResult HitResult);

public:
	// Cable to spawn
	UPROPERTY(EditDefaultsOnly, Category="Cable")
	TSubclassOf<AActor> SpearCable;
	// Get line trace for spearhook
	
	void GetLineTraceForSpearHook();
	FVector GetSpearHookingHorizontalAddVelocity(float deltaTime);
	FHitResult SpearHookHit;
	//UFUNCTION(Unreliable, Server, WithValidation)
	//void ServerSetMoveDirection(const FVector MoveDir);
#pragma endregion

#pragma region Private Variables
	// The direction the character is currently wall running in
	FVector WallRunDirection;
	// The side of the wall the player is running on.
	EWallRunSide WallRunSide;
	// Saves last input for boost direction
	UPROPERTY(BlueprintReadOnly, Category = "My Character Movement|Boost", Meta = (AllowPrivateAccess = "true"))
	FVector MoveDirection;
	
#pragma endregion
};