610 lines
19 KiB
C++
610 lines
19 KiB
C++
// © 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 "AnimInstances/OLSBaseLayerAnimInstance.h"
|
|
|
|
#include "KismetAnimationLibrary.h"
|
|
#include "Components/OLSLocomotionComponent.h"
|
|
#include "Libraries/OLSLocomotionBPLibrary.h"
|
|
#include "GameFramework/PawnMovementComponent.h"
|
|
#include "Interfaces/OLSMoveableInterface.h"
|
|
#include "Kismet/KismetSystemLibrary.h"
|
|
#if WITH_EDITOR
|
|
#include "Misc/DataValidation.h"
|
|
#endif
|
|
|
|
#if ENABLE_LOCOMOTION_DEBUG
|
|
static TAutoConsoleVariable<bool> CVarAnimInstanceLocomotionDebug(TEXT("a.AnimInstance.Locomotion.Debug"), false, TEXT("Turn on visualization debugging for Locomotion"));
|
|
#endif
|
|
|
|
UOLSBaseLayerAnimInstance::UOLSBaseLayerAnimInstance(const FObjectInitializer& objectInitializer)
|
|
: Super(objectInitializer)
|
|
{
|
|
bIsOwningPawnOnGround = false;
|
|
bIsOwningPawnCrouching = false;
|
|
bHasAcceleration = false;
|
|
bHasVelocity = false;
|
|
bWasADSLastUpdate = false;
|
|
bIsJumping = false;
|
|
bIsFalling = false;
|
|
bIsRunningIntoWall = false;
|
|
bHasCrouchStateChanged = false;
|
|
bHasADSStateChanged = false;
|
|
bHasLinkedLayerChanged = false;
|
|
bEnableDebug = false;
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeInitializeAnimation()
|
|
{
|
|
// Super::NativeInitializeAnimation();
|
|
// Don't call Super since it is empty.
|
|
|
|
if (const TObjectPtr<APawn> owningPawn = TryGetPawnOwner())
|
|
{
|
|
OwningPawn = owningPawn;
|
|
MovementComponent = owningPawn->GetMovementComponent();
|
|
MoveableInterface.SetObject(owningPawn);
|
|
MoveableInterface.SetInterface(Cast<IOLSMoveableInterface>(owningPawn));
|
|
if (MoveableInterface)
|
|
{
|
|
LocomotionComponent = MoveableInterface->GetLocomotionComponent();
|
|
}
|
|
}
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeUninitializeAnimation()
|
|
{
|
|
// Super::NativeUninitializeAnimation();
|
|
// Don't call Super since it is empty.
|
|
|
|
if (LocomotionComponent)
|
|
{
|
|
LocomotionComponent->GetOnStanceChangedNativeDelegate().RemoveAll(this);
|
|
|
|
LocomotionComponent->GetOnGaitChangedNativeDelegate().RemoveAll(this);
|
|
|
|
LocomotionComponent->GetOnRotationModeChangedNativeDelegate().RemoveAll(this);
|
|
}
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeBeginPlay()
|
|
{
|
|
Super::NativeBeginPlay();
|
|
|
|
if (LocomotionComponent)
|
|
{
|
|
LocomotionComponent->GetOnStanceChangedNativeDelegate().AddWeakLambda(
|
|
this, [this](const EOLSStance& prevStance)
|
|
{
|
|
if (LocomotionComponent)
|
|
{
|
|
Stance = LocomotionComponent->GetStance();
|
|
}
|
|
});
|
|
|
|
LocomotionComponent->GetOnDesiredGaitChangedNativeDelegate().AddWeakLambda(
|
|
this, [this](const EOLSGait& prevDesiredGait)
|
|
{
|
|
if (LocomotionComponent)
|
|
{
|
|
DesiredGait = LocomotionComponent->GetDesiredGait();
|
|
}
|
|
});
|
|
|
|
LocomotionComponent->GetOnGaitChangedNativeDelegate().AddWeakLambda(
|
|
this, [this](const EOLSGait& prevGait)
|
|
{
|
|
if (LocomotionComponent)
|
|
{
|
|
PrevGait = prevGait;
|
|
Gait = LocomotionComponent->GetGait();
|
|
bHasGaitChanged = true;
|
|
}
|
|
});
|
|
|
|
LocomotionComponent->GetOnRotationModeChangedNativeDelegate().AddWeakLambda(
|
|
this, [this](const EOLSRotationMode& prevRotationMode)
|
|
{
|
|
if (LocomotionComponent)
|
|
{
|
|
RotationMode = LocomotionComponent->GetRotationMode();
|
|
CurrentRootYawOffset = RootYawOffsetClamps.GetRootYawOffsetClamp(RotationMode);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeUpdateAnimation(float deltaSeconds)
|
|
{
|
|
// Super::NativeUpdateAnimation(deltaSeconds);
|
|
// Don't call Super since it is empty.
|
|
|
|
if (OwningPawn && MoveableInterface && MovementComponent)
|
|
{
|
|
NativeUpdateLocationData(OwningPawn, deltaSeconds);
|
|
NativeUpdateRotationData(OwningPawn, deltaSeconds);
|
|
NativeUpdateVelocityData(MoveableInterface, OwningPawn, deltaSeconds);
|
|
NativeUpdateAccelerationData(OwningPawn, deltaSeconds);
|
|
NativeUpdateCharacterStateData(MoveableInterface, MovementComponent, deltaSeconds);
|
|
NativeUpdateAimingData(OwningPawn, deltaSeconds);
|
|
}
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateAnimation(float deltaSeconds)
|
|
{
|
|
// Super::NativeThreadSafeUpdateAnimation(deltaSeconds);
|
|
// Don't call Super since it is empty.
|
|
|
|
NativeThreadSafeUpdateLocationData(deltaSeconds);
|
|
NativeThreadSafeUpdateRotationData(deltaSeconds);
|
|
NativeThreadSafeUpdateVelocityData(deltaSeconds);
|
|
NativeThreadSafeUpdateAccelerationData(deltaSeconds);
|
|
NativeThreadSafeUpdateWallDetectionHeuristic(deltaSeconds);
|
|
NativeThreadSafeUpdateCharacterStateData(deltaSeconds);
|
|
NativeThreadSafeUpdateAimingData(deltaSeconds);
|
|
NativeThreadSafeUpdateRootYawOffset(deltaSeconds);
|
|
|
|
bIsFirstUpdate = false;
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativePostEvaluateAnimation()
|
|
{
|
|
// Don't call Super since it's empty.
|
|
|
|
#if WITH_EDITOR
|
|
const TObjectPtr<AActor> owningActor = GetOwningActor();
|
|
if (owningActor)
|
|
{
|
|
const FVector& actorLocation = owningActor->GetActorLocation();
|
|
const FVector& actorForwardDir = owningActor->GetActorForwardVector() * 100.f;
|
|
|
|
UKismetSystemLibrary::DrawDebugArrow(this, actorLocation, actorLocation + actorForwardDir, 0.f, FLinearColor::Black, 0.f, 1.f);
|
|
|
|
const TObjectPtr<USkeletalMeshComponent> owningComponent = GetOwningComponent();
|
|
if (owningComponent)
|
|
{
|
|
const FVector& rightDir = UKismetMathLibrary::GetRightVector(owningComponent->GetSocketRotation(SKEL_RootBoneName)) * 100.f;
|
|
UKismetSystemLibrary::DrawDebugArrow(this, actorLocation, actorLocation + rightDir, 0.f, FLinearColor::Red, 0.f, 1.f);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeUpdateRotationData(APawn* owningPawn, const float deltaSeconds)
|
|
{
|
|
OwningPawnRotation = owningPawn->GetActorRotation();
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeUpdateLocationData(APawn* owningPawn, const float deltaSeconds)
|
|
{
|
|
OwningPawnLocation = owningPawn->GetActorLocation();
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeUpdateVelocityData(const TScriptInterface<IOLSMoveableInterface>& moveableInterface,
|
|
APawn* owningPawn, const float deltaSeconds)
|
|
{
|
|
OwningPawnVelocity = owningPawn->GetVelocity();
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeUpdateAccelerationData(APawn* owningPawn, const float deltaSeconds)
|
|
{
|
|
OwningPawnAcceleration = MoveableInterface->GetCurrentAcceleration();
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeUpdateCharacterStateData(
|
|
const TScriptInterface<IOLSMoveableInterface>& moveableInterface, UPawnMovementComponent* movementComponent,
|
|
const float deltaSeconds)
|
|
{
|
|
OwningPawnMovementMode = moveableInterface->GetMovementMode();
|
|
|
|
bIsOwningPawnOnGround = movementComponent->IsMovingOnGround();
|
|
bIsOwningPawnCrouching = movementComponent->IsCrouching();
|
|
bIsOwningOrientRotationToMovement = moveableInterface->IsOrientRotationToMovement();
|
|
|
|
OwningPawnGravityZ = movementComponent->GetGravityZ();
|
|
OwningPawnMaxSpeed = movementComponent->GetMaxSpeed();
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeUpdateAimingData(APawn* owningPawn, const float deltaSeconds)
|
|
{
|
|
OwningPawnAimRotation = owningPawn->GetBaseAimRotation();
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateRotationData(const float deltaSeconds)
|
|
{
|
|
if (bIsFirstUpdate)
|
|
{
|
|
YawDeltaSinceLastUpdate = 0.f;
|
|
YawDeltaSpeed = 0.f;
|
|
return;
|
|
}
|
|
|
|
YawDeltaSinceLastUpdate = OwningPawnRotation.Yaw - WorldRotation.Yaw;
|
|
|
|
YawDeltaSpeed = UKismetMathLibrary::SafeDivide(YawDeltaSinceLastUpdate, deltaSeconds);
|
|
AdditiveLeanAngle = YawDeltaSpeed * ((bIsOwningPawnCrouching) ? .025f : .0375f);
|
|
|
|
WorldRotation = OwningPawnRotation;
|
|
|
|
// Call custom logic on blueprint.
|
|
BlueprintThreadSafeUpdateRotationData(deltaSeconds);
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateLocationData(const float deltaSeconds)
|
|
{
|
|
if (bIsFirstUpdate)
|
|
{
|
|
DisplacementSinceLastUpdate = 0.f;
|
|
DisplacementSpeed = 0.f;
|
|
return;
|
|
}
|
|
|
|
DisplacementSinceLastUpdate = (OwningPawnLocation - WorldLocation).Size2D();
|
|
|
|
WorldLocation = OwningPawnLocation;
|
|
|
|
DisplacementSpeed = UKismetMathLibrary::SafeDivide(DisplacementSinceLastUpdate, deltaSeconds);
|
|
|
|
// Call custom logic on blueprint.
|
|
BlueprintThreadSafeUpdateLocationData(deltaSeconds);
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateVelocityData(const float deltaSeconds)
|
|
{
|
|
const bool wasMovingLastUpdate = !LocalVelocity2D.IsNearlyZero(1.e-4f);
|
|
if (wasMovingLastUpdate)
|
|
{
|
|
StopLocalVelocityCardinalDirection = LocalVelocityDirection;
|
|
}
|
|
|
|
WorldVelocity = OwningPawnVelocity;
|
|
|
|
const FVector worldVelocity2D = WorldVelocity * FVector(1.f, 1.f, 0.f);
|
|
LocalVelocity2D = UKismetMathLibrary::LessLess_VectorRotator(worldVelocity2D, WorldRotation);
|
|
|
|
LocalVelocityDirectionAngle = UKismetAnimationLibrary::CalculateDirection(worldVelocity2D, WorldRotation);
|
|
LocalVelocityDirectionAngleWithOffset = LocalVelocityDirectionAngle - RootYawOffset;
|
|
|
|
LocalVelocityDirection = UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(LocalVelocityDirectionAngleWithOffset,
|
|
CardinalDirectionDeadZone,
|
|
LocalVelocityDirection,
|
|
wasMovingLastUpdate);
|
|
|
|
LocalVelocityDirectionNoOffset = UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(
|
|
LocalVelocityDirectionAngle,
|
|
CardinalDirectionDeadZone,
|
|
LocalVelocityDirection,
|
|
wasMovingLastUpdate);
|
|
|
|
bHasVelocity = !FMath::IsNearlyZero(LocalVelocity2D.SizeSquared2D());
|
|
|
|
// Call custom logic on blueprint.
|
|
BlueprintThreadSafeUpdateVelocityData(deltaSeconds);
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateAccelerationData(const float deltaSeconds)
|
|
{
|
|
const FVector worldAcceleration2D = OwningPawnAcceleration * FVector(1.f, 1.f, 0.f);
|
|
|
|
LocalAcceleration2D = UKismetMathLibrary::LessLess_VectorRotator(worldAcceleration2D, WorldRotation);
|
|
|
|
bHasAcceleration = (!FMath::IsNearlyZero(LocalAcceleration2D.SizeSquared2D(), .000001f));
|
|
|
|
PivotDirection2D =
|
|
UKismetMathLibrary::Normal(UKismetMathLibrary::VLerp(PivotDirection2D, UKismetMathLibrary::Normal(worldAcceleration2D), .5f));
|
|
|
|
CardinalDirectionFromAcceleration = (IsLookingOrAimingDirection()
|
|
? UOLSLocomotionBPLibrary::GetOppositeCardinalDirectional(
|
|
UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(
|
|
UKismetAnimationLibrary::CalculateDirection(PivotDirection2D, WorldRotation),
|
|
CardinalDirectionDeadZone, EOLSCardinalDirection::EForward))
|
|
: EOLSCardinalDirection::EBackward);
|
|
|
|
// Call custom logic on blueprint.
|
|
BlueprintThreadSafeUpdateAccelerationData(deltaSeconds);
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateWallDetectionHeuristic(const float deltaSeconds)
|
|
{
|
|
const bool hasAccelerationPassedThreshold = (LocalAcceleration2D.Size2D() > .1f);
|
|
const bool hasVelocityBelowThreshold = (LocalVelocity2D.Size2D() < 200.f);
|
|
|
|
const FVector normalLocalAcceleration2D = UKismetMathLibrary::Normal(LocalAcceleration2D);
|
|
const FVector normalLocalVelocity2D = UKismetMathLibrary::Normal(LocalVelocity2D);
|
|
const bool isDotProductInRange = UKismetMathLibrary::InRange_FloatFloat(
|
|
UKismetMathLibrary::Dot_VectorVector(
|
|
normalLocalAcceleration2D, normalLocalVelocity2D),
|
|
-.6f, .6f);
|
|
|
|
bIsRunningIntoWall = hasAccelerationPassedThreshold && hasVelocityBelowThreshold && isDotProductInRange;
|
|
|
|
// Call custom logic on blueprint.
|
|
BlueprintThreadSafeUpdateWallDetectionHeuristic(deltaSeconds);
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateCharacterStateData(const float deltaSeconds)
|
|
{
|
|
// Locomotion Component Data.
|
|
{
|
|
bHasGaitChanged = (Gait != LastGait);
|
|
LastGait = Gait;
|
|
|
|
bHasRotationModeChanged = (RotationMode != LastRotationMode);
|
|
LastRotationMode = RotationMode;
|
|
}
|
|
|
|
// Crouch state.
|
|
{
|
|
const bool wasCrouchingLastUpdate = bIsCrouching;
|
|
bIsCrouching = bIsOwningPawnCrouching;
|
|
bHasCrouchStateChanged = (bIsCrouching != wasCrouchingLastUpdate);
|
|
}
|
|
|
|
// ADS state.
|
|
{
|
|
bHasADSStateChanged = (bGameplayTag_IsADS != bWasADSLastUpdate);
|
|
bWasADSLastUpdate = bGameplayTag_IsADS;
|
|
}
|
|
|
|
// Weapon fired state.
|
|
{
|
|
TimeSinceFiredWeapon = (bGameplayTag_IsFiring) ? 0.f : TimeSinceFiredWeapon + deltaSeconds;
|
|
}
|
|
|
|
// In air state.
|
|
{
|
|
bIsJumping = false;
|
|
bIsFalling = false;
|
|
|
|
if (OwningPawnMovementMode == MOVE_Falling)
|
|
{
|
|
if (WorldVelocity.Z > 0.f)
|
|
{
|
|
bIsJumping = true;
|
|
}
|
|
else
|
|
{
|
|
bIsFalling = true;
|
|
}
|
|
|
|
// Update Jump Fall Data.
|
|
{
|
|
if (bIsJumping)
|
|
{
|
|
TimeToJumpApex = UKismetMathLibrary::SafeDivide(0.f - WorldVelocity.Z, OwningPawnGravityZ);
|
|
}
|
|
else
|
|
{
|
|
TimeToJumpApex = 0.f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Call custom logic on blueprint.
|
|
BlueprintThreadSafeUpdateCharacterData(deltaSeconds);
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateAimingData(const float deltaSeconds)
|
|
{
|
|
AimPitch = UKismetMathLibrary::NormalizeAxis(OwningPawnRotation.Pitch);
|
|
|
|
// Call custom logic on blueprint.
|
|
BlueprintThreadSafeUpdateAimingData(deltaSeconds);
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateRootYawOffset(const float deltaSeconds)
|
|
{
|
|
if (RootYawOffsetMode == EOLSRootYawOffsetMode::EAccumulate)
|
|
{
|
|
SetRootYawOffset(RootYawOffset - YawDeltaSinceLastUpdate);
|
|
}
|
|
|
|
if (RootYawOffsetMode == EOLSRootYawOffsetMode::EBlendOut)
|
|
{
|
|
SetRootYawOffset(
|
|
UKismetMathLibrary::FloatSpringInterp(RootYawOffset,
|
|
0.f,
|
|
RootYawOffsetSpringState,
|
|
80.f,
|
|
1.f,
|
|
deltaSeconds,
|
|
1.f,
|
|
.5f));
|
|
}
|
|
|
|
RootYawOffsetMode = EOLSRootYawOffsetMode::EBlendOut;
|
|
}
|
|
|
|
UPawnMovementComponent* UOLSBaseLayerAnimInstance::GetMovementComponent() const
|
|
{
|
|
return MovementComponent;
|
|
}
|
|
|
|
const FVector& UOLSBaseLayerAnimInstance::GetWorldVelocity() const
|
|
{
|
|
return WorldVelocity;
|
|
}
|
|
|
|
const float& UOLSBaseLayerAnimInstance::GetLocalVelocityDirectionAngle() const
|
|
{
|
|
return LocalVelocityDirectionAngle;
|
|
}
|
|
|
|
const float& UOLSBaseLayerAnimInstance::GetDisplacementSpeed() const
|
|
{
|
|
return DisplacementSpeed;
|
|
}
|
|
|
|
const FVector& UOLSBaseLayerAnimInstance::GetLocalAcceleration2D() const
|
|
{
|
|
return LocalAcceleration2D;
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::IsLookingOrAimingDirection() const
|
|
{
|
|
return (IsLookingDirection() || IsAimingDirection());
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::IsVelocityOrLookingDirection() const
|
|
{
|
|
return (IsVelocityDirection() || IsLookingDirection());
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::IsVelocityOrAimingDirection() const
|
|
{
|
|
return (IsVelocityDirection() || IsAimingDirection());
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::IsAimingDirection() const
|
|
{
|
|
return (RotationMode == EOLSRotationMode::EAiming);
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::IsLookingDirection() const
|
|
{
|
|
return (RotationMode == EOLSRotationMode::ELookingDirection);
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::IsVelocityDirection() const
|
|
{
|
|
return (RotationMode == EOLSRotationMode::EVelocityDirection);
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::IsCrouching() const
|
|
{
|
|
return bIsCrouching;
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::HasVelocity() const
|
|
{
|
|
return bHasVelocity;
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::HasAcceleration() const
|
|
{
|
|
return bHasAcceleration;
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::ShouldDistanceMatchStop() const
|
|
{
|
|
return HasVelocity() && !HasAcceleration();
|
|
}
|
|
|
|
bool UOLSBaseLayerAnimInstance::IsMovingPerpendicularToInitialPivot() const
|
|
{
|
|
const bool isPivotFwdOrBwd = (PivotInitialDirection == EOLSCardinalDirection::EForward || PivotInitialDirection == EOLSCardinalDirection::EBackward);
|
|
const bool isVelocityFwdOrBwd = (LocalVelocityDirection == EOLSCardinalDirection::EForward || LocalVelocityDirection == EOLSCardinalDirection::EBackward);
|
|
const bool isPivotLeftOrRight = (PivotInitialDirection == EOLSCardinalDirection::ELeft || PivotInitialDirection == EOLSCardinalDirection::ERight);
|
|
const bool isVelocityLeftOrRight = (LocalVelocityDirection == EOLSCardinalDirection::ELeft || LocalVelocityDirection == EOLSCardinalDirection::ERight);
|
|
return (isPivotFwdOrBwd && !isVelocityFwdOrBwd) || (isPivotLeftOrRight && !isVelocityLeftOrRight);
|
|
}
|
|
|
|
const EOLSRotationMode& UOLSBaseLayerAnimInstance::GetRotationMode() const
|
|
{
|
|
return RotationMode;
|
|
}
|
|
|
|
const float& UOLSBaseLayerAnimInstance::GetOwningPawnMaxSpeed() const
|
|
{
|
|
return OwningPawnMaxSpeed;
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::SetRootYawOffset(const float rootYawOffset)
|
|
{
|
|
if (!bEnableRootYawOffset)
|
|
{
|
|
RootYawOffset = 0.f;
|
|
AimYaw = 0.f;
|
|
return;
|
|
}
|
|
|
|
const FVector2D& rootYawOffsetClamp = CurrentRootYawOffset.GetRootYawOffsetClamp(Stance);
|
|
const float normalRootYawOffset = UKismetMathLibrary::NormalizeAxis(rootYawOffset);
|
|
RootYawOffset = (rootYawOffsetClamp.X == rootYawOffsetClamp.Y) ? normalRootYawOffset : FMath::Clamp(normalRootYawOffset, rootYawOffsetClamp.X, rootYawOffsetClamp.Y);
|
|
|
|
AimYaw = RootYawOffset * -1.f;
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::ProcessTurnYawCurve()
|
|
{
|
|
float previousTurnYawCurveValue = TurnYawCurveValue;
|
|
const float turnYawWeightCurveValue = GetCurveValue(TurnYawWeightCurveName);
|
|
if (FMath::IsNearlyZero(turnYawWeightCurveValue, 0.0001f))
|
|
{
|
|
TurnYawCurveValue = 0.f;
|
|
previousTurnYawCurveValue = 0.f;
|
|
return;
|
|
}
|
|
|
|
const float remainingTurnYawCurveValue = GetCurveValue(RemainingTurnYawCurveName);
|
|
TurnYawCurveValue = UKismetMathLibrary::SafeDivide(remainingTurnYawCurveValue, turnYawWeightCurveValue);
|
|
|
|
// Avoid applying the curve delta when the curve first becomes relevant. E.g.
|
|
// When a turn animation starts, the previous curve value will be 0 and the current value will be 90,
|
|
// but no actual rotation has happened yet.
|
|
if (previousTurnYawCurveValue != 0.f)
|
|
{
|
|
// Reduce the target yaw offset by the amount of rotation from the turn animation.
|
|
SetRootYawOffset(RootYawOffset - (TurnYawCurveValue - previousTurnYawCurveValue));
|
|
}
|
|
}
|
|
|
|
void UOLSBaseLayerAnimInstance::ProcessTurnYawCurve_ForwardFacing()
|
|
{
|
|
float previousTurnYawCurveValue = TurnYawCurveValue;
|
|
const float turnYawWeightCurveValue = GetCurveValue(TurnYawWeightCurveName);
|
|
if (FMath::IsNearlyZero(turnYawWeightCurveValue, 0.0001f))
|
|
{
|
|
TurnYawCurveValue = 0.f;
|
|
previousTurnYawCurveValue = 0.f;
|
|
|
|
// When the animation blends in, we could have near-zero weights.
|
|
// When this value is goes up, and then down to 0, we know.
|
|
if (MaxTurnYawValue != 0.f)
|
|
{
|
|
bHasReachedEndTurn = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const float remainingTurnYawCurveValue = GetCurveValue(RemainingTurnYawCurveName);
|
|
TurnYawCurveValue = UKismetMathLibrary::SafeDivide(remainingTurnYawCurveValue, turnYawWeightCurveValue);
|
|
|
|
if (FMath::Abs(TurnYawCurveValue) > FMath::Abs(MaxTurnYawValue))
|
|
{
|
|
MaxTurnYawValue = TurnYawCurveValue;
|
|
}
|
|
|
|
// Avoid applying the curve delta when the curve first becomes relevant. E.g.
|
|
// When a turn animation starts, the previous curve value will be 0 and the current value will be 90,
|
|
// but no actual rotation has happened yet.
|
|
if (previousTurnYawCurveValue != 0.f)
|
|
{
|
|
const float actualAngle = UKismetMathLibrary::SafeDivide(LocalVelocityDirectionAngleWithOffset,
|
|
TurnYawCurveValue) * (TurnYawCurveValue - previousTurnYawCurveValue);
|
|
const float minAngle = FMath::Abs(LocalVelocityDirectionAngleWithOffset) * -1.f;
|
|
const float maxAngle = FMath::Abs(LocalVelocityDirectionAngleWithOffset);
|
|
// Reduce the target yaw offset by the amount of rotation from the turn animation.
|
|
SetRootYawOffset(RootYawOffset - FMath::Clamp(actualAngle, minAngle, maxAngle));
|
|
}
|
|
}
|
|
}
|
|
|
|
float UOLSBaseLayerAnimInstance::CalculateMeshSpaceBlendWeight(const FName localSpaceLayerCurveName) const
|
|
{
|
|
// If this condition fails so MeshSpace will be prioritized.
|
|
if (localSpaceLayerCurveName.IsNone())
|
|
{
|
|
return 1.f;
|
|
}
|
|
|
|
const int32 localSpaceCurveValue = FMath::FloorToInt(GetCurveValue(localSpaceLayerCurveName));
|
|
return 1 - localSpaceCurveValue;
|
|
}
|
|
|
|
UOLSLocomotionComponent* UOLSBaseLayerAnimInstance::ThreadSafeGetLocomotionComponent() const
|
|
{
|
|
return LocomotionComponent;
|
|
}
|