Skip to content

How to customize Motion movement behavior

Practical examples of frequently requested modifications to Motion's movement system.

Behavior-defining defaults live on component profile assets. For project tuning, duplicate the assigned Motion profile into your project content, edit the duplicate, and assign it back to the component's Profile property. See Component profiles for the complete profile workflow.

Use the section that matches the behavior you need. Each recipe stands on its own.

Adding Stamina Drain to Sprint

Motion's sprint component includes built-in stamina support. Here's how to enable and customize it.

Enable Stamina System

  1. Duplicate the assigned sprint profile.
  2. Set bUseStaminaSystem = true.
  3. Configure stamina thresholds:
PropertyDescriptionShipped default
MinStaminaToSprintStamina needed 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

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

Blueprint: React to Exhaustion

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

Modifying Jump Behavior

Add Multi-Jump

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 when performing a jump. It derives CharacterMovementComponent->JumpZVelocity from the value cached at initialization plus the assigned profile's multiplier and modifier, so use the 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.

Adding Movement Speed Buffs/Debuffs

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 using 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 overrides the effect spec's duration only when Duration is positive; pass 0 to keep the GameplayEffect asset's configured duration.

Remove the stored SpeedBuffHandle later with RemoveActiveGameplayEffect after checking that the handle is valid.

Creating Custom Movement States

Add a New State Tag

  1. Define your tag in your project's 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 application requirements do not automatically prevent Motion's built-in components from entering their states. Add a check for your custom tag in C++ overrides such as CanStartSprinting() or CanPerformJump(), and add an equivalent gate to any crouch or custom input path that should be blocked.

Integrating with 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 checks. For a Blueprint-only project, gate the input execution before calling the Motion component, or expose a project-specific C++ function that performs the tag check.

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());
        }
    }
}

Adjusting 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());
}

Adding 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

Extending 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() and the protected UpdateSprintingState(float DeltaTime) require a C++ child class; they 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 when a customization needs exact API or Gameplay Ability System details.

Motion - Advanced First Person Character Controller