A project using this tutorial series is tracked on GitHub. The revision after this part is adc6a0b.

Hej!

At this point we have a solid base, however there are a few quirks to address. One is that we fall when walking down stairs and slopes. Slopes are basically very tiny stairs so we can generalize it to just step down when there's a small enough change in elevation.

Code

We will perform a step-down by doing an extra ground check, but sweep for a longer height, and adjust our location by the height difference of the current location and the hit location.

Ground Check Height

To facilitate this we first need to modify our ground check function to take an optional height parameter:

cpp
1
bool CheckForGround(FHitResult& OutHit, const float Height = 5.0f) const;

Then we just swap our previous ZOffset with Height:

cpp
123456789
bool USimpleMovementComponent::CheckForGround(FHitResult& OutHit, const float Height) const
{
  if (!UpdatedCollider)
  {
    return false;
  }

  const FVector Offset = FVector::UpVector * Height;
  ...

Step Down function

Next up we'll create a variable to contain our step height so we can tweak it to our liking. In our movement component header add (below the other UPROPERTY variables):

cpp
12
UPROPERTY(EditAnywhere, Category="Movement")
float MaxStepDownHeight;

For the default I chose a value of 20:

cpp
1234
USimpleMovementComponent::USimpleMovementComponent(): MoveSpeed(600.0f), JumpForce(420.0f), MaxCeilingStopAngle(5.0f),
                                                      MaxStepDownHeight(20.0f)
{
}

We also need a step-down function (below our Move function declaration):

cpp
1
void StepDown();

The implementation does a ground check with our step-down height, calculate the correction based on the height difference, and move our component:

cpp
1234567891011121314
void USimpleMovementComponent::StepDown()
{
  FHitResult GroundHit;
  CheckForGround(GroundHit, MaxStepDownHeight);

  if (GroundHit.IsValidBlockingHit())
  {
    const FVector Diff = GroundHit.Location - GroundHit.TraceStart;
    const FVector StepCorrection = FVector::UpVector * -FMath::Abs(Diff.Z);

    const FRotator& Rotation = UpdatedComponent->GetComponentRotation();
    SafeMoveUpdatedComponent(StepCorrection, Rotation, true, GroundHit);
  }
}

Results

We can now walk down slopes:

As well as stairs:

Note: for smoother movement I recommend keeping the step height low and make the hit-boxes of stairs into slopes whenever possible. Step-down is mostly useful to even out the bumps on the ground.