Merge movement-component #1
|
@ -3,13 +3,22 @@
|
||||||
|
|
||||||
#include "NakatomiCMC.h"
|
#include "NakatomiCMC.h"
|
||||||
|
|
||||||
|
#include <Components/CapsuleComponent.h>
|
||||||
#include <GameFramework/Character.h>
|
#include <GameFramework/Character.h>
|
||||||
|
#include "NakatomiCharacter.h"
|
||||||
|
|
||||||
UNakatomiCMC::UNakatomiCMC(): Safe_bWantsToSprint(false)
|
UNakatomiCMC::UNakatomiCMC(): Safe_bWantsToSprint(false)
|
||||||
{
|
{
|
||||||
NavAgentProps.bCanCrouch = true;
|
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.
|
// 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.
|
// 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,
|
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());
|
UNakatomiCMC* CharacterMovement = Cast<UNakatomiCMC>(C->GetCharacterMovement());
|
||||||
|
|
||||||
Saved_bWantsToSprint = CharacterMovement->Safe_bWantsToSprint;
|
Saved_bWantsToSprint = CharacterMovement->Safe_bWantsToSprint;
|
||||||
|
Saved_bPrevWantsToCrouch = CharacterMovement->Safe_bPrevWantsToCrouch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C)
|
void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C)
|
||||||
|
@ -60,6 +70,7 @@ void UNakatomiCMC::FSavedMove_Nakatomi::PrepMoveFor(ACharacter* C)
|
||||||
UNakatomiCMC* CharacterMovement = Cast<UNakatomiCMC>(C->GetCharacterMovement());
|
UNakatomiCMC* CharacterMovement = Cast<UNakatomiCMC>(C->GetCharacterMovement());
|
||||||
|
|
||||||
CharacterMovement->Safe_bWantsToSprint = Saved_bWantsToSprint;
|
CharacterMovement->Safe_bWantsToSprint = Saved_bWantsToSprint;
|
||||||
|
CharacterMovement->Safe_bPrevWantsToCrouch = Saved_bPrevWantsToCrouch;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNakatomiCMC::FNetworkPredictionData_Client_Nakatomi::FNetworkPredictionData_Client_Nakatomi(
|
UNakatomiCMC::FNetworkPredictionData_Client_Nakatomi::FNetworkPredictionData_Client_Nakatomi(
|
||||||
|
@ -110,6 +121,51 @@ void UNakatomiCMC::OnMovementUpdated(float DeltaSeconds, const FVector& OldLocat
|
||||||
MaxWalkSpeed = Walk_MaxWalkSpeed;
|
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()
|
void UNakatomiCMC::EnableSprint()
|
||||||
|
@ -131,3 +187,101 @@ void UNakatomiCMC::DisableCrouch()
|
||||||
{
|
{
|
||||||
bWantsToCrouch = false;
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
|
#include "Nakatomi.h"
|
||||||
#include "GameFramework/CharacterMovementComponent.h"
|
#include "GameFramework/CharacterMovementComponent.h"
|
||||||
#include "NakatomiCMC.generated.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;
|
typedef FSavedMove_Character Super;
|
||||||
|
|
||||||
|
// Flag
|
||||||
uint8 Saved_bWantsToSprint:1;
|
uint8 Saved_bWantsToSprint:1;
|
||||||
|
|
||||||
|
uint8 Saved_bPrevWantsToCrouch:1;
|
||||||
|
|
||||||
virtual bool CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter, float MaxDelta) const override;
|
virtual bool CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter, float MaxDelta) const override;
|
||||||
virtual void Clear() override;
|
virtual void Clear() override;
|
||||||
virtual uint8 GetCompressedFlags() const override;
|
virtual uint8 GetCompressedFlags() const override;
|
||||||
|
@ -37,20 +49,50 @@ class NAKATOMI_API UNakatomiCMC : public UCharacterMovementComponent
|
||||||
virtual FSavedMovePtr AllocateNewMove() override;
|
virtual FSavedMovePtr AllocateNewMove() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly) float Sprint_MaxWalkSpeed;
|
UPROPERTY(EditDefaultsOnly)
|
||||||
UPROPERTY(EditDefaultsOnly) float Walk_MaxWalkSpeed;
|
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_bWantsToSprint;
|
||||||
|
bool Safe_bPrevWantsToCrouch;
|
||||||
|
|
||||||
|
UPROPERTY(Transient)
|
||||||
|
ANakatomiCharacter* NakatomiCharacterOwner;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UNakatomiCMC();
|
UNakatomiCMC();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InitializeComponent() override;
|
||||||
|
|
||||||
FNetworkPredictionData_Client* GetPredictionData_Client() const override;
|
FNetworkPredictionData_Client* GetPredictionData_Client() const override;
|
||||||
protected:
|
protected:
|
||||||
virtual void UpdateFromCompressedFlags(uint8 Flags) override;
|
virtual void UpdateFromCompressedFlags(uint8 Flags) override;
|
||||||
|
|
||||||
virtual void OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity) 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:
|
public:
|
||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
void EnableSprint();
|
void EnableSprint();
|
||||||
|
@ -63,4 +105,17 @@ public:
|
||||||
|
|
||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
void DisableCrouch();
|
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 "CoreMinimal.h"
|
||||||
#include "GameFramework/Character.h"
|
#include "GameFramework/Character.h"
|
||||||
#include "HealthComponent.h"
|
#include "HealthComponent.h"
|
||||||
#include "NakatomiCMC.h"
|
#include "Nakatomi.h"
|
||||||
#include "Throwable.h"
|
#include "Throwable.h"
|
||||||
#include "Weapon.h"
|
#include "Weapon.h"
|
||||||
#include "NakatomiCharacter.generated.h"
|
#include "NakatomiCharacter.generated.h"
|
||||||
|
|
Loading…
Reference in New Issue