OLS/Source/OLSAnimation/Private/Libraries/OLSLocomotionBPLibrary.cpp

150 lines
5.3 KiB
C++
Raw Normal View History

2024-09-22 21:11:19 +00:00
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
#include "Libraries/OLSLocomotionBPLibrary.h"
FVector UOLSLocomotionBPLibrary::PredictGroundMovementStopLocation(const FVector& velocity,
bool shouldUseSeparateBrakingFriction,
float brakingFriction, float groundFriction,
float brakingFrictionFactor,
float brakingDecelerationWalking)
{
FVector predictedStopLocation = FVector::ZeroVector;
// Determine the actual braking friction
float actualBrakingFriction = shouldUseSeparateBrakingFriction ? brakingFriction : groundFriction;
actualBrakingFriction = FMath::Max(0.f, actualBrakingFriction * FMath::Max(0.f, brakingFrictionFactor));
// Calculate 2D velocity and speed
const FVector velocity2D = FVector(velocity.X, velocity.Y, 0.f);
const float speed2D = velocity2D.Size();
// Check if there's movement to stop
if (speed2D > 0.f)
{
// Calculate braking divisor
const float divisor = actualBrakingFriction * speed2D + FMath::Max(0.f, brakingDecelerationWalking);
// Check if stopping is possible
if (divisor > 0.f)
{
// Calculate time to stop
const float timeToStop = speed2D / divisor;
// Calculate predicted stop location
predictedStopLocation = velocity2D * timeToStop + 0.5f * ((-actualBrakingFriction) * velocity2D -
brakingDecelerationWalking * velocity2D.GetSafeNormal()) * FMath::Square(timeToStop);
}
}
return predictedStopLocation;
}
FVector UOLSLocomotionBPLibrary::PredictGroundMovementPivotLocation(const FVector& acceleration,
const FVector& velocity, float groundFriction)
{
FVector predictedPivotLocation = FVector::ZeroVector;
const FVector acceleration2D = acceleration * FVector(1.f, 1.f, 0.f);
const float accelerationSize2D = acceleration2D.Size();
// Check if velocity is along the opposite direction of acceleration
if ((velocity | acceleration2D) < 0.0f)
{
const float speedAlongAcceleration = -(velocity | acceleration2D);
const float divisor = accelerationSize2D + 2.f * speedAlongAcceleration * groundFriction;
// Check if stopping is possible
if (divisor > 0.f)
{
const float timeToDirectionChange = speedAlongAcceleration / divisor;
// Calculate the acceleration force
const FVector accelerationForce = acceleration - (velocity - acceleration2D * velocity.Size2D()) * groundFriction;
// Calculate the predicted pivot location
predictedPivotLocation = velocity * timeToDirectionChange + 0.5f * accelerationForce * timeToDirectionChange * timeToDirectionChange;
}
}
return predictedPivotLocation;
}
EOLSCardinalDirection UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(float angle,
float deadZone,
EOLSCardinalDirection currentDirection,
bool useCurrentDirection /* = false */)
{
const float absAngle = FMath::Abs(angle);
float fwdDeadZone = deadZone;
float bwdDeadZone = deadZone;
if (useCurrentDirection)
{
if (currentDirection == EOLSCardinalDirection::EForward)
{
fwdDeadZone *= 2.f;
}
else if (currentDirection == EOLSCardinalDirection::EBackward)
{
bwdDeadZone *= 2.f;
}
}
if(absAngle <= (45 + fwdDeadZone))
{
return EOLSCardinalDirection::EForward;
}
else if (absAngle >= (135 - bwdDeadZone))
{
return EOLSCardinalDirection::EBackward;
}
else if (angle > 0)
{
return EOLSCardinalDirection::ERight;
}
return EOLSCardinalDirection::ELeft;
}
EOLSCardinalDirection UOLSLocomotionBPLibrary::GetOppositeCardinalDirectional(EOLSCardinalDirection currentDirection)
{
switch (currentDirection)
{
case EOLSCardinalDirection::EForward: {return EOLSCardinalDirection::EBackward;}
case EOLSCardinalDirection::EBackward: {return EOLSCardinalDirection::EForward;}
case EOLSCardinalDirection::ELeft: {return EOLSCardinalDirection::ERight;}
case EOLSCardinalDirection::ERight: {return EOLSCardinalDirection::ELeft;}
}
return EOLSCardinalDirection::EForward;
}
EOLSHipDirection UOLSLocomotionBPLibrary::GetOppositeHipDirection(EOLSHipDirection currentHipDirection)
{
return (currentHipDirection == EOLSHipDirection::EForward ? EOLSHipDirection::EBackward : EOLSHipDirection::EForward);
}
void UOLSLocomotionBPLibrary::TryLinkAnimLayer(USkeletalMeshComponent* mesh,
TSubclassOf<UAnimInstance> animClass,
FName groupName,
bool shouldUnlinkGroupIfInvalid)
{
if (!animClass->IsValidLowLevelFast())
{
if (shouldUnlinkGroupIfInvalid)
{
if (const TObjectPtr<UAnimInstance> linkedAnimInstance = mesh->GetLinkedAnimLayerInstanceByGroup(groupName))
{
mesh->UnlinkAnimClassLayers(linkedAnimInstance.GetClass());
}
}
return;
}
mesh->LinkAnimClassLayers(animClass);
}