Skip to content

Commit

Permalink
I have restored the position correction process during multiplayer th…
Browse files Browse the repository at this point in the history
…at was accidentally deleted, and also reinstated the initial speed limit function which seemed to be better to have.
  • Loading branch information
SAM-tak committed Mar 17, 2024
1 parent 904d8b1 commit 9927ffa
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 6 deletions.
104 changes: 98 additions & 6 deletions Source/ALS/Private/AlsCharacter_Actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,29 @@ void AAlsCharacter::StartRagdollingImplementation()

AnimationInstance->UnFreezeRagdolling();

// Initialize Ragdolling State

RagdollingState.PullForce = 0.0f;
RagdollingState.ElapsedTime = 0.0f;
RagdollingState.TimeAfterGrounded = RagdollingState.TimeAfterGroundedAndStopped = 0.0f;
RagdollingState.bFacingUpward = RagdollingState.bGrounded = false;
RagdollingState.bFreezing = false;
RagdollingState.PrevActorLocation = GetActorLocation();

if (Settings->Ragdolling.bLimitInitialRagdollSpeed)
{
// Limit the ragdoll's speed for a few frames, because for some unclear reason,
// it can get a much higher initial speed than the character's last speed.
// TODO Find a better solution or wait for a fix in future engine versions.

auto& MinSpeedLimit{Settings->Ragdolling.MinSpeedLimit};

RagdollingState.SpeedLimitFrameTimeRemaining = Settings->Ragdolling.SpeedLimitDurationFrame;
RagdollingState.SpeedLimit = FMath::Max(MinSpeedLimit, LocomotionState.Velocity.Size());

LimitRagdollSpeed();
}

// Initialize bFacingUpward flag by current movement direction. If Velocity is Zero, it is chosen bFacingUpward is true.
// And determine target yaw angle of the character.

Expand Down Expand Up @@ -757,12 +780,6 @@ void AAlsCharacter::StartRagdollingImplementation()

SetLocomotionAction(AlsLocomotionActionTags::Ragdolling);

RagdollingState.ElapsedTime = 0.0f;
RagdollingState.TimeAfterGrounded = RagdollingState.TimeAfterGroundedAndStopped = 0.0f;
RagdollingState.bFacingUpward = RagdollingState.bGrounded = false;
RagdollingState.bFreezing = false;
RagdollingState.PrevActorLocation = GetActorLocation();

OnRagdollingStarted();
}

Expand Down Expand Up @@ -822,6 +839,47 @@ void AAlsCharacter::RefreshRagdolling(const float DeltaTime)
RagdollingState.bGrounded = bGrounded;
SetActorLocation(NewActorLocation, true);

// Zero target location means that it hasn't been replicated yet, so we can't apply the logic below.

if (!bLocallyControlled && !RagdollTargetLocation.IsZero())
{
// Apply ragdoll location corrections.

auto& PullForce{Settings->Ragdolling.TargetPullForce};
auto& InterpolationSpeed{Settings->Ragdolling.PullForceInterpolationSpeed};

RagdollingState.PullForce = FMath::FInterpTo(RagdollingState.PullForce, PullForce, DeltaTime, InterpolationSpeed);

const auto HorizontalSpeedSquared{AlsCharacterMovement->Velocity.SizeSquared2D()};

const auto PullForceBoneName{
HorizontalSpeedSquared > FMath::Square(300.0f) ? UAlsConstants::Spine03BoneName() : UAlsConstants::PelvisBoneName()
};

auto* PullForceBody{GetMesh()->GetBodyInstance(PullForceBoneName)};

FPhysicsCommand::ExecuteWrite(PullForceBody->ActorHandle, [this](const FPhysicsActorHandle& ActorHandle)
{
if (!FPhysicsInterface::IsRigidBody(ActorHandle))
{
return;
}

const auto PullForceVector{
RagdollTargetLocation - FPhysicsInterface::GetTransform_AssumesLocked(ActorHandle, true).GetLocation()
};

auto& MinPullForceDistance{Settings->Ragdolling.MinPullForceDistance};
auto& MaxPullForceDistance{Settings->Ragdolling.MaxPullForceDistance};

if (PullForceVector.SizeSquared() > FMath::Square(MinPullForceDistance))
{
FPhysicsInterface::AddForce_AssumesLocked(
ActorHandle, PullForceVector.GetClampedToMaxSize(MaxPullForceDistance) * RagdollingState.PullForce, true, true);
}
});
}

if (IsRagdollingGroundedAndAged())
{
// Determine whether the ragdoll is facing upward or downward.
Expand All @@ -846,6 +904,15 @@ void AAlsCharacter::RefreshRagdolling(const float DeltaTime)
}
}

// Limit the speed of ragdoll bodies.

if (RagdollingState.SpeedLimitFrameTimeRemaining > 0)
{
RagdollingState.SpeedLimitFrameTimeRemaining -= 1;

LimitRagdollSpeed();
}

AnimationInstance->UpdateRagdollingAnimationState(RagdollingState);

if (Settings->Ragdolling.bAllowFreeze)
Expand Down Expand Up @@ -932,6 +999,31 @@ FVector AAlsCharacter::RagdollTraceGround(bool& bGrounded) const
};
}

void AAlsCharacter::LimitRagdollSpeed() const
{
GetMesh()->ForEachBodyBelow(NAME_None, true, false, [this](FBodyInstance* Body)
{
FPhysicsCommand::ExecuteWrite(Body->ActorHandle, [this](const FPhysicsActorHandle& ActorHandle)
{
if (!FPhysicsInterface::IsRigidBody(ActorHandle))
{
return;
}

auto Velocity{FPhysicsInterface::GetLinearVelocity_AssumesLocked(ActorHandle)};
if (Velocity.SizeSquared() <= FMath::Square(RagdollingState.SpeedLimit))
{
return;
}

Velocity.Normalize();
Velocity *= RagdollingState.SpeedLimit;

FPhysicsInterface::SetLinearVelocity_AssumesLocked(ActorHandle, Velocity);
});
});
}

bool AAlsCharacter::IsRagdollingAllowedToStop() const
{
return LocomotionAction == AlsLocomotionActionTags::Ragdolling;
Expand Down
1 change: 1 addition & 0 deletions Source/ALS/Public/AlsCharacter.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ class ALS_API AAlsCharacter : public ACharacter

bool IsRagdollingGroundedAndAged() const;

void LimitRagdollSpeed() const;

// Debug

Expand Down
24 changes: 24 additions & 0 deletions Source/ALS/Public/Settings/AlsRagdollingSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ struct ALS_API FAlsRagdollingSettings
Meta = (ClampMin = 0, EditCondition = "bStartRagdollingOnLand", ForceUnits = "cm/s"))
float RagdollingOnLandSpeedThreshold{1000.0f};

// If checked, the ragdoll's speed will be limited by the character's last speed for a few frames
// after activation. This hack is used to prevent the ragdoll from getting a very high initial speed
// at unstable FPS, which can be reproduced by jumping and activating the ragdoll at the same time.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS")
uint8 bLimitInitialRagdollSpeed : 1 {true};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS|LimitInitialRagdollSpeed", Meta = (ClampMin = 0, EditCondition = "bLimitInitialRagdollSpeed"))
float MinSpeedLimit{200.0f};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS|LimitInitialRagdollSpeed", Meta = (ClampMin = 0, EditCondition = "bLimitInitialRagdollSpeed"))
int32 SpeedLimitDurationFrame{8};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS")
TEnumAsByte<ECollisionChannel> GroundTraceChannel{ECC_Visibility};

Expand All @@ -34,6 +46,18 @@ struct ALS_API FAlsRagdollingSettings
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS")
TObjectPtr<UAnimMontage> GetUpBackMontage{nullptr};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS|Multiply")
float TargetPullForce{750.0f};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS|Multiply")
float PullForceInterpolationSpeed{0.6f};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS|Multiply", Meta = (ClampMin = 0, ForceUnits = "cm"))
float MinPullForceDistance{5.0f};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS|Multiply", Meta = (ClampMin = 0, ForceUnits = "cm"))
float MaxPullForceDistance{50.0f};

// If checked, it stops the physical simulation and returns control of the bone to kinematic
// when the conditions mentioned later are met.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS")
Expand Down
8 changes: 8 additions & 0 deletions Source/ALS/Public/State/AlsRagdollingState.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ USTRUCT(BlueprintType)
struct ALS_API FAlsRagdollingState
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS", Meta = (ForceUnits = "N"))
float PullForce{0.0f};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS", Meta = (ClampMin = 0))
int32 SpeedLimitFrameTimeRemaining{0};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS", Meta = (ClampMin = 0, ForceUnits = "cm/s"))
float SpeedLimit{0.0f};

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ALS", Meta = (ForceUnits = "deg"))
float LyingDownYawAngleDelta{0.0f};
Expand Down

0 comments on commit 9927ffa

Please sign in to comment.