How can I create a Smooth Crouch?

Hi. I’m trying to write a custom crouch function, and as far as I understand, the Crouch function used by ACharacter class changes 2 things: BaseEyeHeight and HalfHeight on the CapsuleComponent; I used FMath::FInterpTo function to make a smooth transition between being crouching or not. The problem is, once the BaseEyeHeight==CrouchedEyeHeight, and HalfHeight==CrouchedHalfHeight, the CapsuleComponent stands floating, does not get to the floor, and as soon as I move it, it snaps to the floor. I Guess I have to find a way to move the character (or the CapsuleComponent, I’m not sure which one) towards the floor as the character starts to crouch or stops crouching. Here is my code:

Character.h

#include "GameFramework/Character.h"
#include "PrototypeChar.generated.h"

/**
 * 
 */
UCLASS()
class APrototypeChar : public ACharacter
{
	GENERATED_UCLASS_BODY()

protected:
	//Temp Variables;
	float DecBEH;
	float DecCapsHeight;

	//Boolean used if crouching key is being pressed
	bool bIsCrouching;

	//Functions used for crouching
	void CrouchStart();
	void CrouchEnd();
	void CrouchImpl(float DeltaTime);

	//Inputs
	virtual void SetupPlayerInputComponent(class UInputComponent *InputComponent);

	//Tick Function
	virtual void Tick(float DeltaTime) OVERRIDE;
};

Character.cpp

#include "Prototipo.h"
#include "PrototypeChar.h"
#include "PrototypePlayerController.h"


APrototypeChar::APrototypeChar(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	

	CapsuleComponent->InitCapsuleSize(40.0f, 85.0f);
	CapsuleComponent->SetHiddenInGame(false);

	CharacterMovement->NavAgentProps.bCanCrouch = true;
	CharacterMovement->CrouchedSpeedMultiplier = 0.5f;

	bIsCrouching = false;

	DecBEH = BaseEyeHeight;
	DecCapsHeight = CapsuleComponent->GetUnscaledCapsuleHalfHeight();

	
	
}

void APrototypeChar::SetupPlayerInputComponent(class UInputComponent *InputComponent)
{
	check(InputComponent);
	InputComponent->BindAction("Crouch", IE_Pressed, this, &APrototypeChar::CrouchStart);
	InputComponent->BindAction("Crouch", IE_Released, this, &APrototypeChar::CrouchEnd);
}

void APrototypeChar::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	
	if (Controller)
	{
		CrouchImpl(DeltaTime);
	}
}

void APrototypeChar::CrouchStart()
{
	if (Controller != NULL)
	{	
		bIsCrouching = true;
	}
}	


void APrototypeChar::CrouchEnd()
{
	if (Controller != NULL)
	{
		bIsCrouching = false;
	}
}

void APrototypeChar::CrouchImpl(float DeltaTime)
{
	const float TargetBEH = bIsCrouching ? CrouchedEyeHeight : DecBEH;
	const float TargetCapsuleSize = bIsCrouching ? CharacterMovement->CrouchedHalfHeight: DecCapsHeight;
	if (Controller)
	{
		BaseEyeHeight = FMath::FInterpTo(BaseEyeHeight, TargetBEH, DeltaTime, 10.0f);
		CapsuleComponent->SetCapsuleHalfHeight(FMath::FInterpTo(CapsuleComponent->GetUnscaledCapsuleHalfHeight(), TargetCapsuleSize, DeltaTime, 10.0f), true);
	}
}

I hope someone could help me to find a way to set the character or the CapsuleComponent on the floor WHILE the FInterpTo is happening. Thanks!!

Read the character movement component in source to see how it moves the player on the standard method.

The last post in this thread explains one way to do it.
https://forums.unrealengine.com/showthread.php?11931-Tiny-capsule-component-offset

Thanks, I’ve found a way to do it, here is the code, in case someone wants to use it:

void APrototypeChar::CrouchImpl(float DeltaTime)
{
	const float TargetBEH = bIsCrouching ? CrouchedEyeHeight : DecBEH;
	const float TargetCapsuleSize = bIsCrouching ? CharacterMovement->CrouchedHalfHeight : DecCapsHeight;
	if (Controller != NULL)
	{
		BaseEyeHeight = FMath::FInterpTo(BaseEyeHeight, TargetBEH, DeltaTime, 10.0f);
		CapsuleComponent->SetCapsuleHalfHeight(FMath::FInterpTo(CapsuleComponent->GetUnscaledCapsuleHalfHeight(), TargetCapsuleSize, DeltaTime, 10.0f), true);
		// Dist and DeltaMovCaps are used for the interpolation value added to RelativeLocation.Z
		const float Dist = TargetCapsuleSize - CapsuleComponent->GetUnscaledCapsuleHalfHeight();
		const float DeltaMovCaps = Dist*FMath::Clamp<float>(DeltaTime*10.0f, 0.f, 1.f);
		CapsuleComponent->SetRelativeLocation(FVector(CapsuleComponent->RelativeLocation.X, CapsuleComponent->RelativeLocation.Y, (CapsuleComponent->RelativeLocation.Z + DeltaMovCaps)),true);
	}
}
1 Like