OLS/Source/OLSAnimation/Private/AnimInstances/OLSBaseLayerAnimInstance.cpp

623 lines
20 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 "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
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();
2024-11-28 17:57:33 +00:00
DesiredMaxSpeed = LocomotionComponent->GetMaxSpeedByGait(DesiredGait);
2024-09-22 21:11:19 +00:00
}
});
LocomotionComponent->GetOnGaitChangedNativeDelegate().AddWeakLambda(
this, [this](const EOLSGait& prevGait)
{
if (LocomotionComponent)
{
PrevGait = prevGait;
Gait = LocomotionComponent->GetGait();
bHasGaitChanged = true;
2024-11-28 17:57:33 +00:00
DesiredMaxSpeed = LocomotionComponent->GetMaxSpeedByGait(Gait);
2024-09-22 21:11:19 +00:00
}
});
LocomotionComponent->GetOnRotationModeChangedNativeDelegate().AddWeakLambda(
this, [this](const EOLSRotationMode& prevRotationMode)
{
if (LocomotionComponent)
{
RotationMode = LocomotionComponent->GetRotationMode();
2024-10-28 20:24:41 +00:00
bHasRotationModeChanged = true;
2024-09-22 21:11:19 +00:00
}
});
}
}
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);
2024-10-23 22:41:23 +00:00
NativeThreadSafeUpdateRootYawOffset(deltaSeconds);
2024-09-22 21:11:19 +00:00
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();
2024-11-28 17:57:33 +00:00
InputAmount = FMath::GetMappedRangeValueClamped(FVector2D(0.f, MoveableInterface->GetMaxAcceleration()),
FVector2D(0.f, 1.f),
MoveableInterface->GetCurrentAcceleration().Size());
2024-09-22 21:11:19 +00:00
}
void UOLSBaseLayerAnimInstance::NativeUpdateCharacterStateData(
const TScriptInterface<IOLSMoveableInterface>& moveableInterface, UPawnMovementComponent* movementComponent,
const float deltaSeconds)
{
OwningPawnMovementMode = moveableInterface->GetMovementMode();
bIsOwningPawnOnGround = movementComponent->IsMovingOnGround();
bIsOwningPawnCrouching = movementComponent->IsCrouching();
2024-10-23 22:41:23 +00:00
bIsOwningOrientRotationToMovement = moveableInterface->IsOrientRotationToMovement();
2024-09-22 21:11:19 +00:00
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);
2024-10-23 22:41:23 +00:00
LocalVelocityDirectionAngleWithOffset = LocalVelocityDirectionAngle - RootYawOffset;
LocalVelocityDirection = UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(LocalVelocityDirectionAngleWithOffset,
CardinalDirectionDeadZone,
LocalVelocityDirection,
wasMovingLastUpdate);
LocalVelocityDirectionNoOffset = UOLSLocomotionBPLibrary::SelectCardinalDirectionFromAngle(
LocalVelocityDirectionAngle,
CardinalDirectionDeadZone,
LocalVelocityDirection,
wasMovingLastUpdate);
2024-11-29 19:30:36 +00:00
bHasVelocity = (LocalVelocity2D.SizeSquared2D() > KINDA_SMALL_NUMBER);
2024-09-22 21:11:19 +00:00
// 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);
2024-11-29 19:30:36 +00:00
bHasAcceleration = (LocalAcceleration2D.SizeSquared2D() > KINDA_SMALL_NUMBER);
2024-09-22 21:11:19 +00:00
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);
2024-11-23 17:42:10 +00:00
if (HasAcceleration())
{
const float directionSign = FMath::Sign(
UKismetAnimationLibrary::CalculateDirection(OwningPawnAcceleration, WorldRotation));
TurnDirection = FMath::FloorToInt(directionSign);
LocalAccelerationDirection = UKismetAnimationLibrary::CalculateDirection(
OwningPawnAcceleration.GetSafeNormal2D(), WorldRotation);
2024-11-23 17:42:10 +00:00
}
2024-11-28 17:57:33 +00:00
const float desiredMaxSpeed = DesiredMaxSpeed * InputAmount;
2024-11-29 19:30:36 +00:00
if (LocalAcceleration2D.GetSafeNormal2D().Dot(LocalVelocity2D.GetSafeNormal2D()) < -0.2f && WorldVelocity.Size2D() >
2024-11-28 17:57:33 +00:00
desiredMaxSpeed * 0.5f && HasAcceleration() && !bIsPivoting)
2024-11-23 17:42:10 +00:00
{
bIsPivoting = true;
}
2024-11-29 19:30:36 +00:00
else if (LocalAcceleration2D.GetSafeNormal2D().Dot(LocalVelocity2D.GetSafeNormal2D()) >= 0.f || !HasAcceleration() && bIsPivoting)
2024-11-23 17:42:10 +00:00
{
bIsPivoting = false;
}
2024-09-22 21:11:19 +00:00
// 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;
}
2024-11-28 17:57:33 +00:00
const bool wasPivotingLastUpdate = bWasPivoting;
bWasPivoting = (bIsPivoting != wasPivotingLastUpdate);
2024-09-22 21:11:19 +00:00
// 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);
}
2024-10-23 22:41:23 +00:00
void UOLSBaseLayerAnimInstance::NativeThreadSafeUpdateRootYawOffset(const float deltaSeconds)
{
if (RootYawOffsetMode == EOLSRootYawOffsetMode::EAccumulate)
{
SetRootYawOffset(RootYawOffset - YawDeltaSinceLastUpdate);
}
if (RootYawOffsetMode == EOLSRootYawOffsetMode::EBlendOut)
{
SetRootYawOffset(
UKismetMathLibrary::FloatSpringInterp(RootYawOffset,
0.f,
2024-10-24 02:34:02 +00:00
RootYawOffsetSpringState,
2024-10-23 22:41:23 +00:00
80.f,
1.f,
deltaSeconds,
1.f,
.5f));
}
RootYawOffsetMode = EOLSRootYawOffsetMode::EBlendOut;
}
2024-09-22 21:11:19 +00:00
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;
}
2024-10-23 22:41:23 +00:00
void UOLSBaseLayerAnimInstance::SetRootYawOffset(const float rootYawOffset)
{
if (!bEnableRootYawOffset)
{
RootYawOffset = 0.f;
AimYaw = 0.f;
return;
}
const float normalRootYawOffset = UKismetMathLibrary::NormalizeAxis(rootYawOffset);
2024-10-26 00:55:47 +00:00
RootYawOffset = (RootYawOffsetAngleClamp.X == RootYawOffsetAngleClamp.Y) ? normalRootYawOffset : FMath::Clamp(normalRootYawOffset, RootYawOffsetAngleClamp.X, RootYawOffsetAngleClamp.Y);
2024-10-23 22:41:23 +00:00
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, KINDA_SMALL_NUMBER))
2024-10-23 22:41:23 +00:00
{
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.
2024-10-24 02:34:02 +00:00
if (MaxTurnYawValue != 0.f)
2024-10-23 22:41:23 +00:00
{
bHasReachedEndTurn = true;
}
}
2024-10-24 02:34:02 +00:00
else
2024-10-23 22:41:23 +00:00
{
2024-10-24 02:34:02 +00:00
const float remainingTurnYawCurveValue = GetCurveValue(RemainingTurnYawCurveName);
TurnYawCurveValue = UKismetMathLibrary::SafeDivide(remainingTurnYawCurveValue, turnYawWeightCurveValue);
2024-10-23 22:41:23 +00:00
2024-10-24 02:34:02 +00:00
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));
}
}
2024-10-23 22:41:23 +00:00
}
2024-09-22 21:11:19 +00:00
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;
}