// 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 };