265 lines
7.6 KiB
C++
265 lines
7.6 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
#include "Player/LMMovementComponent.h"
|
|
|
|
#include "Components/CapsuleComponent.h"
|
|
#include "Player/LMPlayer.h"
|
|
|
|
|
|
#pragma region Saved Move
|
|
|
|
ULMMovementComponent::FSavedMove_Legumix::FSavedMove_Legumix()
|
|
{
|
|
Saved_bPrevWantsToCrouch = 0;
|
|
}
|
|
|
|
// Checks the current move and the new move to see if they can be combined
|
|
bool ULMMovementComponent::FSavedMove_Legumix::CanCombineWith(const FSavedMovePtr& NewMove, ACharacter* InCharacter, float MaxDelta) const
|
|
{
|
|
return FSavedMove_Character::CanCombineWith(NewMove, InCharacter, MaxDelta);
|
|
}
|
|
|
|
void ULMMovementComponent::FSavedMove_Legumix::Clear()
|
|
{
|
|
FSavedMove_Character::Clear();
|
|
}
|
|
|
|
uint8 ULMMovementComponent::FSavedMove_Legumix::GetCompressedFlags() const
|
|
{
|
|
return FSavedMove_Character::GetCompressedFlags();
|
|
}
|
|
|
|
void ULMMovementComponent::FSavedMove_Legumix::SetMoveFor(ACharacter* C, float InDeltaTime, FVector const& NewAccel, FNetworkPredictionData_Client_Character& ClientData)
|
|
{
|
|
FSavedMove_Character::SetMoveFor(C, InDeltaTime, NewAccel, ClientData);
|
|
const ULMMovementComponent* CharacterMovement = Cast<ULMMovementComponent>(C->GetCharacterMovement());
|
|
|
|
Saved_bPrevWantsToCrouch = CharacterMovement->Safe_bPrevWantsToCrouch;
|
|
}
|
|
|
|
void ULMMovementComponent::FSavedMove_Legumix::PrepMoveFor(ACharacter* C)
|
|
{
|
|
FSavedMove_Character::PrepMoveFor(C);
|
|
ULMMovementComponent* CharacterMovement = Cast<ULMMovementComponent>(C->GetCharacterMovement());
|
|
CharacterMovement->Safe_bPrevWantsToCrouch = Saved_bPrevWantsToCrouch;
|
|
}
|
|
|
|
#pragma endregion
|
|
|
|
#pragma region Client Network Prediction Data
|
|
|
|
ULMMovementComponent::FNetworkPredictionData_Client_Legumix::FNetworkPredictionData_Client_Legumix(const UCharacterMovementComponent& ClientMovement)
|
|
: Super(ClientMovement)
|
|
{
|
|
}
|
|
|
|
FSavedMovePtr ULMMovementComponent::FNetworkPredictionData_Client_Legumix::AllocateNewMove()
|
|
{
|
|
return FSavedMovePtr(new FSavedMove_Legumix());
|
|
}
|
|
|
|
#pragma endregion
|
|
|
|
#pragma region CMC
|
|
|
|
ULMMovementComponent::ULMMovementComponent()
|
|
{
|
|
PrimaryComponentTick.bCanEverTick = true;
|
|
NavAgentProps.bCanCrouch = true;
|
|
}
|
|
|
|
FNetworkPredictionData_Client* ULMMovementComponent::GetPredictionData_Client() const
|
|
{
|
|
check(PawnOwner != nullptr);
|
|
|
|
if (ClientPredictionData == nullptr)
|
|
{
|
|
ULMMovementComponent* MutableThis = const_cast<ULMMovementComponent*>(this);
|
|
|
|
MutableThis->ClientPredictionData = new FNetworkPredictionData_Client_Legumix(*this);
|
|
MutableThis->ClientPredictionData->MaxSmoothNetUpdateDist = 92.f;
|
|
MutableThis->ClientPredictionData->MaxSmoothNetUpdateDist = 140.f;
|
|
}
|
|
return ClientPredictionData;
|
|
}
|
|
|
|
|
|
void ULMMovementComponent::InitializeComponent()
|
|
{
|
|
Super::InitializeComponent();
|
|
CharacterOwner = Cast<ALMPlayer>(GetOwner());
|
|
}
|
|
|
|
void ULMMovementComponent::UpdateFromCompressedFlags(uint8 Flags)
|
|
{
|
|
Super::UpdateFromCompressedFlags(Flags);
|
|
}
|
|
|
|
|
|
void ULMMovementComponent::OnMovementUpdated(float DeltaSeconds, const FVector& OldLocation, const FVector& OldVelocity)
|
|
{
|
|
Super::OnMovementUpdated(DeltaSeconds, OldLocation, OldVelocity);
|
|
|
|
Safe_bPrevWantsToCrouch = bWantsToCrouch;
|
|
}
|
|
|
|
bool ULMMovementComponent::IsMovingOnGround() const
|
|
{
|
|
return Super::IsMovingOnGround() || IsCustomMovementMode(ECustomMovementModes::ECMM_Sliding);
|
|
}
|
|
|
|
bool ULMMovementComponent::CanCrouchInCurrentState() const
|
|
{
|
|
return Super::CanCrouchInCurrentState() && IsMovingOnGround();
|
|
}
|
|
|
|
void ULMMovementComponent::UpdateCharacterStateBeforeMovement(float DeltaSeconds)
|
|
{
|
|
UE_LOG(LogTemp, Log, TEXT("Velocity %f vs %f"), Velocity.SizeSquared(), pow(SlideMinSpeed, 2))
|
|
if (MovementMode == EMovementMode::MOVE_Walking && Safe_bPrevWantsToCrouch)
|
|
{
|
|
FHitResult PotentialSlideSurface;
|
|
UE_LOG(LogTemp, Display, TEXT("PotentialSlideSurface"));
|
|
if (Velocity.SizeSquared() > pow(SlideMinSpeed, 2) && GetSlideSurface(PotentialSlideSurface))
|
|
{
|
|
EnterSlide();
|
|
}
|
|
}
|
|
|
|
if (IsCustomMovementMode(ECustomMovementModes::ECMM_Sliding) && !bWantsToCrouch)
|
|
{
|
|
ExitSlide();
|
|
}
|
|
|
|
Super::UpdateCharacterStateBeforeMovement(DeltaSeconds);
|
|
}
|
|
|
|
void ULMMovementComponent::PhysCustom(float DeltaTime, int32 Iterations)
|
|
{
|
|
Super::PhysCustom(DeltaTime, Iterations);
|
|
|
|
switch (CustomMovementMode)
|
|
{
|
|
case ECustomMovementModes::ECMM_Sliding:
|
|
PhysSlide(DeltaTime, Iterations);
|
|
break;
|
|
default:
|
|
UE_LOG(LogTemp, Fatal, TEXT("Invalid Movement Mode"))
|
|
}
|
|
}
|
|
|
|
bool ULMMovementComponent::IsCustomMovementMode(ECustomMovementModes InCustomMovementMode) const
|
|
{
|
|
return MovementMode == EMovementMode::MOVE_Custom && CustomMovementMode == InCustomMovementMode;
|
|
}
|
|
|
|
void ULMMovementComponent::EnterSlide()
|
|
{
|
|
UE_LOG(LogTemp, Error, TEXT("Entering Slide"));
|
|
bWantsToCrouch = true;
|
|
Velocity += Velocity.GetSafeNormal2D() * SlideEnterImpulse;
|
|
SetMovementMode(EMovementMode::MOVE_Custom, ECustomMovementModes::ECMM_Sliding);
|
|
}
|
|
|
|
void ULMMovementComponent::ExitSlide()
|
|
{
|
|
UE_LOG(LogTemp, Error, TEXT("Exiting Slide"));
|
|
bWantsToCrouch = false;
|
|
|
|
FQuat NewRotation = FRotationMatrix::MakeFromXZ(UpdatedComponent->GetForwardVector().GetSafeNormal2D(), FVector::UpVector).ToQuat();
|
|
FHitResult Hit;
|
|
SafeMoveUpdatedComponent(FVector::ZeroVector, NewRotation, true, Hit);
|
|
SetMovementMode(EMovementMode::MOVE_Walking);
|
|
}
|
|
|
|
void ULMMovementComponent::PhysSlide(float DeltaTime, int32 Iterations)
|
|
{
|
|
if (DeltaTime < MIN_TICK_TIME)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// RestorePreAdditiveRootMotionVelocity();
|
|
|
|
FHitResult SurfaceHit;
|
|
if (!GetSlideSurface(SurfaceHit) || Velocity.SizeSquared() < pow(SlideMinSpeed, 2))
|
|
{
|
|
ExitSlide();
|
|
StartNewPhysics(DeltaTime, Iterations);
|
|
return;
|
|
}
|
|
|
|
// Surface Gravity
|
|
Velocity += SlideGravityForce * FVector::DownVector * DeltaTime;
|
|
|
|
// Strafe
|
|
if (FMath::Abs(FVector::DotProduct(Acceleration.GetSafeNormal(), UpdatedComponent->GetRightVector())) > .5f)
|
|
{
|
|
Acceleration = Acceleration.ProjectOnTo(UpdatedComponent->GetRightVector());
|
|
}
|
|
else
|
|
{
|
|
Acceleration = FVector::ZeroVector;
|
|
}
|
|
|
|
// Calc Velocity
|
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
|
{
|
|
// bFluid == true because friction isn't applied if we are not in a fluid
|
|
CalcVelocity(DeltaTime, SlideFriction, true, GetMaxBrakingDeceleration());
|
|
}
|
|
// ApplyRootMotionToVelocity(DeltaTime);
|
|
|
|
// Perform Move
|
|
Iterations++;
|
|
bJustTeleported = false;
|
|
|
|
FVector OldLocation = UpdatedComponent->GetComponentLocation();
|
|
FQuat OldRotation = UpdatedComponent->GetComponentRotation().Quaternion();
|
|
FHitResult Hit(1.f);
|
|
FVector Adjusted = Velocity * DeltaTime;
|
|
FVector VelPlaneDir = FVector::VectorPlaneProject(Velocity, SurfaceHit.Normal).GetSafeNormal();
|
|
FQuat NewRotation = FRotationMatrix::MakeFromXZ(VelPlaneDir, SurfaceHit.Normal).ToQuat();
|
|
|
|
// The most important method to move the character
|
|
SafeMoveUpdatedComponent(Adjusted, NewRotation, true, Hit);
|
|
|
|
if (Hit.Time < 1.f)
|
|
{
|
|
HandleImpact(Hit, DeltaTime, Adjusted);
|
|
SlideAlongSurface(Adjusted, (1.f - Hit.Time), Hit.Normal, Hit, true);
|
|
}
|
|
|
|
FHitResult NewSurfaceHit;
|
|
if (!GetSlideSurface(NewSurfaceHit) || Velocity.SizeSquared() < pow(SlideMinSpeed, 2))
|
|
{
|
|
ExitSlide();
|
|
}
|
|
|
|
// Update Outgoing Velocity & Acceleration
|
|
if (!bJustTeleported && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity())
|
|
{
|
|
Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation) / DeltaTime;
|
|
}
|
|
}
|
|
|
|
bool ULMMovementComponent::GetSlideSurface(FHitResult& Hit) const
|
|
{
|
|
FVector Start = UpdatedComponent->GetComponentLocation();
|
|
FVector End = Start + CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() * 2.f * FVector::DownVector;
|
|
FName ProfileName = TEXT("BlockAll");
|
|
return GetWorld()->LineTraceSingleByProfile(Hit, Start, End, ProfileName , PlayerCharacterOwner->GetIgnoreCharacterParams());
|
|
}
|
|
|
|
#pragma endregion
|
|
|
|
#pragma region Input
|
|
void ULMMovementComponent::CrouchPressed()
|
|
{
|
|
bWantsToCrouch = !bWantsToCrouch;
|
|
}
|
|
|
|
#pragma endregion
|
|
|