Skip to content

How to customize Motion movement behavior

This guide gives practical examples of common changes to the Motion movement system.

Component profile assets contain behavior defaults. To adjust a project, duplicate the assigned Motion profile in project content. Edit the duplicate and assign it to the component Profile property. See Component profiles for the profile procedure.

Use the section that matches the applicable behavior. Each procedure is independent.

Add stamina drain to sprint

The Motion sprint component includes stamina support. Use this procedure to enable and adjust it.

Enable the stamina system

  1. Duplicate the assigned sprint profile.
  2. Set bUseStaminaSystem = true.
  3. Configure stamina thresholds:
PropertyDescriptionSupplied default
MinStaminaToSprintMinimum stamina to start1.5
MinStaminaToStopSprintingStamina to CONTINUE (hysteresis)0.25
RegenDelayDurationSeconds before regen after exhaustion2.0

Configure stamina effects

Assign these GameplayEffects on the sprint profile:

SprintStaminaDrainEffect = GE_Motion_SprintStaminaDrain
StaminaRegenEffect = GE_Motion_SprintStaminaRegen
StaminaRegenDelayEffect = GE_Motion_SprintStaminaRegenDelay

Set a custom drain rate

Create a custom GameplayEffect Blueprint:

  1. Duplicate GE_Motion_SprintStaminaDrain
  2. Modify the periodic effect magnitude
  3. Assign your custom effect to the sprint profile

React to exhaustion in Blueprint

text
Event OnSprintStaminaDepletedDelegate
├── Play Sound (Exhaustion_SFX)
├── Play Camera Shake (Exhaustion_Shake)
└── Show UI Warning

Modify jump behavior

Add multiple jumps

Duplicate the assigned jump profile, then:

  1. Set MaxAdditionalJumps = 1 for double jump, or more for triple jump.
  2. Optionally set AdditionalJumpVelocityMultiplier = 0.8, or lower for weaker subsequent jumps.

Adjust Jump Height

Method 1: Jump profile values

JumpVelocityMultiplier = 1.2  // Multiply base jump velocity by 1.2
// OR
JumpVelocityModifier = 200.0  // Add 200 units to jump velocity

MotionJumpComponent does not read the JumpVelocity attribute during a jump. It calculates CharacterMovementComponent->JumpZVelocity from the initial stored value and profile modifiers. Thus, use profile values for the built-in jump path.

Add Coyote Time

On the assigned jump profile:

  1. Set CoyoteTime = 0.15 seconds after leaving ground, or 0 to disable.

Add Jump Buffer

On the assigned jump profile:

  1. Set JumpBufferTime = 0.2 seconds before landing, or 0 to disable.

Add movement speed effects

Create Speed Modifier Effect

  1. Create new GameplayEffect Blueprint
  2. Configure:
    • Duration: Duration or Infinite
    • Modifier: Attribute = WalkSpeed, Op = Additive or Multiplicative
    • Magnitude: Set By Caller with SetByCaller.Magnitude.WalkSpeed

Apply from Blueprint

text
Get Ability System Component
├── Make Outgoing Spec (YourSpeedEffect, Level 1)
├── Assign Set By Caller Magnitude (SetByCaller.Magnitude.WalkSpeed, SpeedBonus)
└── Apply Gameplay Effect Spec to Self → Store Handle (for later removal)

Apply from C++

cpp
// Apply speed buff
void ApplySpeedBuff(float SpeedBonus, float Duration)
{
    if (UAbilitySystemComponent* ASC = UMotionAbilitySystemHelper::GetAbilitySystemComponentFromActor(Character))
    {
        FGameplayEffectContextHandle Context = ASC->MakeEffectContext();
        FGameplayEffectSpecHandle Spec = ASC->MakeOutgoingSpec(SpeedBuffEffect, 1.0f, Context);
        if (!Spec.IsValid())
        {
            return;
        }

        Spec.Data->SetSetByCallerMagnitude(
            MotionGameplayTags::SetByCaller_Magnitude_WalkSpeed,
            SpeedBonus
        );
        if (Duration > 0.0f)
        {
            Spec.Data->SetDuration(Duration, true);
        }

        SpeedBuffHandle = ASC->ApplyGameplayEffectSpecToSelf(*Spec.Data.Get());
    }
}

The C++ example replaces the effect duration only when Duration is positive. Pass 0 to keep the configured GameplayEffect duration.

Make sure that the handle is valid. Then, remove the stored SpeedBuffHandle with RemoveActiveGameplayEffect.

Create custom movement states

Add a New State Tag

  1. Define the tag in the project GameplayTags:

    Motion.State.Sliding
    Motion.State.WallRunning
    Motion.State.Swimming
  2. Create an Infinite GameplayEffect, add a Target Tags Gameplay Effect Component, and add your state tag to its granted tags.

React to Custom State

In Animation Blueprint

Add to GameplayTagPropertyMap:

Tag: Motion.State.Sliding
Property: bIsSliding (Bool)

In Other Components

cpp
bool bIsSliding = UMotionAbilitySystemHelper::ActorHasGameplayTag(
    Character,
    FGameplayTag::RequestGameplayTag(FName(TEXT("Motion.State.Sliding")))
);

Block Other States

GameplayEffect requirements do not automatically stop built-in Motion component states. Evaluate the custom tag in C++ overrides such as CanStartSprinting() or CanPerformJump(). Add an equivalent condition to applicable crouch or custom input paths.

Integrate ability cooldowns

Register the cooldown tags used by your project, then create Duration GameplayEffects that grant those tags through a Target Tags Gameplay Effect Component.

Sprint with Cooldown

Override CanStartSprinting() in a C++ child class (Blueprint override not supported):

cpp
// In your C++ child class
class UMySprintComponent : public UMotionSprintingComponent
{
protected:
    virtual bool CanStartSprinting() const override
    {
        if (UAbilitySystemComponent* ASC = CachedAbilitySystemComponent)
        {
            if (ASC->HasMatchingGameplayTag(FGameplayTag::RequestGameplayTag(FName(TEXT("Ability.Cooldown.Sprint")))))
            {
                return false;
            }
        }
        return Super::CanStartSprinting();
    }
};

Jump with Cooldown

Override CanPerformJump() in a C++ child class (Blueprint override not supported):

cpp
// In your C++ child class
class UMyJumpComponent : public UMotionJumpComponent
{
protected:
    virtual bool CanPerformJump() const override
    {
        if (UAbilitySystemComponent* ASC = CachedAbilitySystemComponent)
        {
            if (ASC->HasMatchingGameplayTag(FGameplayTag::RequestGameplayTag(FName(TEXT("Ability.Cooldown.Jump")))))
            {
                return false;
            }
        }
        return Super::CanPerformJump();
    }
};

Blueprint child classes cannot override these functions. For a Blueprint-only project, add the condition before you call the Motion component. Alternatively, expose a project C++ function that evaluates the tag.

Apply Cooldown After Action

cpp
void ApplyCooldown(TSubclassOf<UGameplayEffect> CooldownEffect)
{
    if (UAbilitySystemComponent* ASC = CachedAbilitySystemComponent)
    {
        FGameplayEffectContextHandle Context = ASC->MakeEffectContext();
        FGameplayEffectSpecHandle Spec = ASC->MakeOutgoingSpec(CooldownEffect, 1.0f, Context);
        if (Spec.IsValid())
        {
            ASC->ApplyGameplayEffectSpecToSelf(*Spec.Data.Get());
        }
    }
}

Adjust crouch speed

Change Speed Modifier

On the assigned crouch profile:

CrouchWalkSpeedModifier = -200.0 (negative to slow down)

Variable Crouch Speed

Create a custom GameplayEffect with SetByCaller magnitude:

cpp
// Apply variable crouch speed
FGameplayEffectContextHandle Context = ASC->MakeEffectContext();
FGameplayEffectSpecHandle Spec = ASC->MakeOutgoingSpec(CrouchSpeedEffect, 1.0f, Context);
if (Spec.IsValid())
{
    Spec.Data->SetSetByCallerMagnitude(
        MotionGameplayTags::SetByCaller_Magnitude_CrouchSpeed,
        CalculatedSpeedModifier
    );
    ASC->ApplyGameplayEffectSpecToSelf(*Spec.Data.Get());
}

Add camera effects to movement

Sprint Camera Shake

On the assigned sprint profile:

  1. Set bApplyCameraShake = true.
  2. Configure the SprintCameraShake curve.

Landing Camera Impact

The MotionJumpComponent already broadcasts landing events. Subscribe in Blueprint:

text
Event OnLandedDelegate
├── Get Character Movement Component
├── Get Last Update Velocity → Calculate Impact from Z velocity
├── Create Landing Camera Curve
└── Add Motion Curve on MotionCameraComponent

Extend component behavior

Blueprint Child Class

  1. Create a Blueprint child of a Motion component.
  2. Bind its Blueprint-assignable delegates, such as OnSprintStateChangedDelegate, to react to state changes.

Virtual functions such as CanStartSprinting() must have a C++ child class. The protected UpdateSprintingState(float DeltaTime) must also have one. These functions are not Blueprint override events.

C++ Child Class

cpp
UCLASS()
class UMySprintComponent : public UMotionSprintingComponent
{
    GENERATED_BODY()

protected:
    virtual void BeginPlay() override
    {
        Super::BeginPlay();
        OnSprintStateChangedDelegate.AddDynamic(this, &UMySprintComponent::HandleSprintStateChanged);
    }

    virtual bool CanStartSprinting() const override
    {
        // Add custom logic
        if (!Super::CanStartSprinting())
            return false;

        // Your project-specific condition.
        return bCanSprintBasedOnEquipment;
    }

    UFUNCTION()
    void HandleSprintStateChanged(bool bIsSprinting)
    {
        // Your custom handling
        if (bIsSprinting)
        {
            // Trigger project-specific sprint feedback.
        }
    }

    UPROPERTY(EditAnywhere, Category = "Sprint")
    bool bCanSprintBasedOnEquipment = true;
};

Next steps

Use the reference pages for exact API or Gameplay Ability System details.

Motion - Advanced First Person Character Controller