Add initial custom slide movement implementation
This commit is contained in:
parent
2cdb97b7ab
commit
293358737c
|
@ -3,13 +3,22 @@
|
|||
|
||||
#include "NakatomiCMC.h"
|
||||
|
||||
#include <Components/CapsuleComponent.h>
|
||||
#include <GameFramework/Character.h>
|
||||
#include "NakatomiCharacter.h"
|
||||
|
||||
UNakatomiCMC::UNakatomiCMC(): Safe_bWantsToSprint(false)
|
||||
{
|
||||
NavAgentProps.bCanCrouch = true;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::InitializeComponent()
|
||||
{
|
||||
Super::InitializeComponent();
|
||||
|
||||
NakatomiCharacterOwner = Cast<ANakatomiCharacter>(GetOwner());
|
||||
}
|
||||
|
||||
// Checks if we can combine the NewMove with the current move to save on data.
|
||||
// If all the data in a saved move is identical, if true, we cam tell the server to run the existing move instead.
|
||||
bool UNakatomiCMC::FSavedMove_Nakatomi::CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter,
|
||||
|
@ -51,6 +60,7 @@ void UNakatomiCMC::FSavedMove_Nakatomi::SetMoveFor(ACharacter* C, float InDeltaT
|
|||
UNakatomiCMC* CharacterMovement = Cast<UNakatomiCMC>(C->GetCharacterMovement());
|
||||
|
||||
Saved_bWantsToSprint = CharacterMovement->Safe_bWantsToSprint;
|
||||
Saved_bPrevWantsToCrouch = CharacterMovement->Safe_bPrevWantsToCrouch;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C)
|
||||
|
@ -60,6 +70,7 @@ void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C)
|
|||
UNakatomiCMC* CharacterMovement = Cast<UNakatomiCMC>(C->GetCharacterMovement());
|
||||
|
||||
CharacterMovement->Safe_bWantsToSprint = Saved_bWantsToSprint;
|
||||
CharacterMovement->Safe_bPrevWantsToCrouch = Saved_bPrevWantsToCrouch;
|
||||
}
|
||||
|
||||
UNakatomiCMC::FNetworkPredictionData_Client_Nakatomi::FNetworkPredictionData_Client_Nakatomi(
|
||||
|
@ -110,6 +121,51 @@ void UNakatomiCMC::OnMovementUpdated(float DeltaSeconds, const FVector& OldLocat
|
|||
MaxWalkSpeed = Walk_MaxWalkSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
Safe_bPrevWantsToCrouch = bWantsToCrouch;
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::IsMovingOnGround() const
|
||||
{
|
||||
return Super::IsMovingOnGround() || IsCustomMovementMode(CMOVE_Slide);
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::CanCrouchInCurrentState() const
|
||||
{
|
||||
return Super::CanCrouchInCurrentState() && IsMovingOnGround();
|
||||
}
|
||||
|
||||
void UNakatomiCMC::UpdateCharacterStateBeforeMovement(float DeltaSeconds)
|
||||
{
|
||||
if (MovementMode == MOVE_Walking && !bWantsToCrouch && Safe_bPrevWantsToCrouch)
|
||||
{
|
||||
FHitResult PotentialSlideSurface;
|
||||
if (Velocity.SizeSquared() > pow(Slide_MinSpeed, 2) && GetSlideSurface(PotentialSlideSurface))
|
||||
{
|
||||
EnterSlide();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsCustomMovementMode(CMOVE_Slide) && !bWantsToCrouch)
|
||||
{
|
||||
ExitSlide();
|
||||
}
|
||||
|
||||
Super::UpdateCharacterStateBeforeMovement(DeltaSeconds);
|
||||
}
|
||||
|
||||
void UNakatomiCMC::PhysCustom(float deltaTime, int32 Iterations)
|
||||
{
|
||||
Super::PhysCustom(deltaTime, Iterations);
|
||||
|
||||
switch (CustomMovementMode)
|
||||
{
|
||||
case CMOVE_Slide:
|
||||
PhysSlide(deltaTime, Iterations);
|
||||
break;
|
||||
default:
|
||||
UE_LOG(LogTemp, Fatal, TEXT("Invalid Movement Mode"));
|
||||
}
|
||||
}
|
||||
|
||||
void UNakatomiCMC::EnableSprint()
|
||||
|
@ -131,3 +187,101 @@ void UNakatomiCMC::DisableCrouch()
|
|||
{
|
||||
bWantsToCrouch = false;
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::IsCustomMovementMode(ECustomMovementMove InCustomMovementMode) const
|
||||
{
|
||||
return MovementMode == MOVE_Custom && CustomMovementMode == InCustomMovementMode;
|
||||
}
|
||||
|
||||
void UNakatomiCMC::EnterSlide()
|
||||
{
|
||||
bWantsToCrouch = true;
|
||||
Velocity += Velocity.GetSafeNormal2D() * Slide_EnterImpulse;
|
||||
SetMovementMode(MOVE_Custom, CMOVE_Slide);
|
||||
}
|
||||
|
||||
void UNakatomiCMC::ExitSlide()
|
||||
{
|
||||
bWantsToCrouch = false;
|
||||
|
||||
FQuat NewRotation = FRotationMatrix::MakeFromXZ(UpdatedComponent->GetForwardVector().GetSafeNormal2D(), FVector::UpVector).ToQuat();
|
||||
FHitResult Hit;
|
||||
SafeMoveUpdatedComponent(FVector::ZeroVector, NewRotation, true, Hit);
|
||||
SetMovementMode(MOVE_Walking);
|
||||
}
|
||||
|
||||
void UNakatomiCMC::PhysSlide(float deltaTime, int32 Iterations)
|
||||
{
|
||||
if (deltaTime < MIN_TICK_TIME) return;
|
||||
|
||||
// This is probably not needed for Sliding but including for completeness, will likely remove later.
|
||||
RestorePreAdditiveRootMotionVelocity();
|
||||
|
||||
FHitResult SurfaceHit;
|
||||
if (!GetSlideSurface(SurfaceHit) || Velocity.SizeSquared() < pow(Slide_MinSpeed, 2))
|
||||
{
|
||||
ExitSlide();
|
||||
StartNewPhysics(deltaTime, Iterations);
|
||||
}
|
||||
|
||||
// Surface Gravity
|
||||
Velocity += Slide_GravityForce * FVector::DownVector * deltaTime;
|
||||
|
||||
// Calculate Strafe
|
||||
if (FMath::Abs(FVector::DotProduct(Acceleration.GetSafeNormal(), UpdatedComponent->GetRightVector())) > 0.5f)
|
||||
{
|
||||
Acceleration = Acceleration.ProjectOnTo(UpdatedComponent->GetRightVector());
|
||||
}
|
||||
else
|
||||
{
|
||||
Acceleration = FVector::ZeroVector;
|
||||
}
|
||||
|
||||
// Calculate Velocity
|
||||
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
||||
{
|
||||
CalcVelocity(deltaTime, Slide_Friction, true, GetMaxBrakingDeceleration());
|
||||
}
|
||||
ApplyRootMotionToVelocity(deltaTime);
|
||||
|
||||
// Perform Move
|
||||
Iterations++;
|
||||
bJustTeleported = false;
|
||||
|
||||
FVector OldLocation = UpdatedComponent->GetComponentLocation();
|
||||
FQuat OldRotation = UpdatedComponent->GetComponentRotation().Quaternion();
|
||||
|
||||
FHitResult Hit(1.f);
|
||||
FVector AdjustedVelocity = Velocity * deltaTime;
|
||||
FVector VelocityPlaneDirection = FVector::VectorPlaneProject(Velocity, SurfaceHit.Normal).GetSafeNormal();
|
||||
FQuat NewRotation = FRotationMatrix::MakeFromXZ(VelocityPlaneDirection, SurfaceHit.Normal).ToQuat();
|
||||
SafeMoveUpdatedComponent(AdjustedVelocity, NewRotation, true, Hit);
|
||||
|
||||
// Post Move Checks
|
||||
if (Hit.Time < 1.f)
|
||||
{
|
||||
HandleImpact(Hit, deltaTime, AdjustedVelocity);
|
||||
SlideAlongSurface(AdjustedVelocity, (1.f - Hit.Time), Hit.Normal, Hit, true);
|
||||
}
|
||||
|
||||
FHitResult NewSurfaceHit;
|
||||
if (!GetSlideSurface(NewSurfaceHit) || Velocity.SizeSquared() < pow(Slide_MinSpeed, 2))
|
||||
{
|
||||
ExitSlide();
|
||||
}
|
||||
|
||||
// Update outgoing Velocity and Acceleration
|
||||
if (!bJustTeleported && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
||||
{
|
||||
Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation) / deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
bool UNakatomiCMC::GetSlideSurface(FHitResult& Hit) const
|
||||
{
|
||||
const FVector Start = UpdatedComponent->GetComponentLocation();
|
||||
const FVector End = Start + CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.f * FVector::DownVector;
|
||||
const FName ProfileName = TEXT("BlockAll");
|
||||
|
||||
return GetWorld()->LineTraceSingleByProfile(Hit, Start, End, ProfileName);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Nakatomi.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "NakatomiCMC.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum ECustomMovementMove
|
||||
{
|
||||
CMOVE_None UMETA(Hidden),
|
||||
CMOVE_Slide UMETA(DisplayName = "Slide"),
|
||||
CMOVE_MAX UMETA(Hidden),
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -18,8 +27,11 @@ class NAKATOMI_API UNakatomiCMC : public UCharacterMovementComponent
|
|||
{
|
||||
typedef FSavedMove_Character Super;
|
||||
|
||||
// Flag
|
||||
uint8 Saved_bWantsToSprint:1;
|
||||
|
||||
uint8 Saved_bPrevWantsToCrouch:1;
|
||||
|
||||
virtual bool CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter, float MaxDelta) const override;
|
||||
virtual void Clear() override;
|
||||
virtual uint8 GetCompressedFlags() const override;
|
||||
|
@ -37,19 +49,49 @@ class NAKATOMI_API UNakatomiCMC : public UCharacterMovementComponent
|
|||
virtual FSavedMovePtr AllocateNewMove() override;
|
||||
};
|
||||
|
||||
UPROPERTY(EditDefaultsOnly) float Sprint_MaxWalkSpeed;
|
||||
UPROPERTY(EditDefaultsOnly) float Walk_MaxWalkSpeed;
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Sprint_MaxWalkSpeed;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Walk_MaxWalkSpeed;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Slide_MinSpeed = 10.f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Slide_EnterImpulse = 2000.f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Slide_GravityForce = 5000.f;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float Slide_Friction = 1.3f;
|
||||
|
||||
bool Safe_bWantsToSprint;
|
||||
bool Safe_bPrevWantsToCrouch;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
ANakatomiCharacter* NakatomiCharacterOwner;
|
||||
|
||||
public:
|
||||
UNakatomiCMC();
|
||||
|
||||
protected:
|
||||
void InitializeComponent() override;
|
||||
|
||||
FNetworkPredictionData_Client* GetPredictionData_Client() const override;
|
||||
protected:
|
||||
virtual void UpdateFromCompressedFlags(uint8 Flags) override;
|
||||
|
||||
virtual void OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity) override;
|
||||
|
||||
virtual bool IsMovingOnGround() const override;
|
||||
|
||||
virtual bool CanCrouchInCurrentState() const override;
|
||||
|
||||
virtual void UpdateCharacterStateBeforeMovement(float DeltaSeconds) override;
|
||||
|
||||
virtual void PhysCustom(float deltaTime, int32 Iterations) override;
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
|
@ -63,4 +105,17 @@ public:
|
|||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void DisableCrouch();
|
||||
|
||||
UFUNCTION()
|
||||
bool IsCustomMovementMode(ECustomMovementMove InCustomMovementMode) const;
|
||||
|
||||
private:
|
||||
|
||||
void EnterSlide();
|
||||
|
||||
void ExitSlide();
|
||||
|
||||
void PhysSlide(float deltaTime, int32 Iterations); // Every movement mode requires a physics function to work
|
||||
|
||||
bool GetSlideSurface(FHitResult& Hit) const;
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "HealthComponent.h"
|
||||
#include "NakatomiCMC.h"
|
||||
#include "Nakatomi.h"
|
||||
#include "Throwable.h"
|
||||
#include "Weapon.h"
|
||||
#include "NakatomiCharacter.generated.h"
|
||||
|
|
Loading…
Reference in New Issue