Skip to content

Runtime Character Speed: Sprint, Slows, and Safe Restoration

A sprint button is easy until a slow, crouch, speed pickup, or network game touches the same value. The durable pattern is to keep the reasons for the speed separate, calculate one effective limit, and let Character Movement turn input into actual motion.

At a glance

Main target: your Character's Character Movement component · Main value: Max Walk Speed, in centimeters per second · Returns: property setters return nothing and do not report success · Does not mean: current speed · Official references: UCharacterMovementComponent and Add Movement Input

The one-minute version

  • Max Walk Speed is the usual cap for ground movement. A normal Unreal unit is one centimeter, so 600 means 600 centimeters per second.
  • Max Acceleration controls how quickly velocity changes toward the input request. It is not another top-speed value.
  • Braking Deceleration Walking and friction control how velocity falls when there is no acceleration, and how an over-speed Character returns toward its cap.
  • Add Movement Input supplies direction and input strength. Making its Scale Value larger does not replace Max Walk Speed with a higher sprint speed.
  • Do not save "whatever Max Walk Speed is now" on sprint press and restore it on release. That saved float becomes stale if another system changes speed before release.
  • Keep BaseWalkSpeed, sprint state, and slow/buff modifiers as separate data. Send every change through one RecalculateMovementSpeed function.
  • In multiplayer, the server owns the accepted gameplay state. Max Walk Speed is not a general replicated gameplay variable by itself, so replicate or otherwise synchronize the state used to calculate it.
  • Animation should read actual velocity, usually Vector Length XY, not treat the configured maximum as the speed the Character achieved.

The four values beginners mix together

These settings cooperate, but they answer different questions:

Value Unit Question it answers
Max Walk Speed cm/s How fast may ordinary walking or running get? It also limits lateral falling speed.
Max Walk Speed Crouched cm/s What ground-speed cap applies while the Character is crouched?
Max Acceleration cm/s² How quickly may velocity change toward the requested movement direction?
Braking Deceleration Walking cm/s² How strongly may walking velocity slow when there is no acceleration?

Ground friction and braking-friction settings also affect starts, turns, and stops. A higher maximum does not guarantee an instant sprint: low acceleration can make the Character take time to reach it. Lowering the maximum does not teleport velocity to the new value either; the movement calculation brings an over-speed Character back toward the allowed speed.

The current movement mode chooses the relevant family of limits. Walking and nav walking use the ground settings; crouched walking uses Max Walk Speed Crouched; swimming, flying, and custom movement have their own settings or logic. Max Walk Speed also caps lateral motion while falling, but it does not replace gravity or vertical velocity.

How input becomes motion

For a normal Character, the useful mental model is:

input action value
-> Add Movement Input builds a pending input vector
-> Character Movement turns that vector into acceleration
-> movement mode, Max Acceleration, friction, and braking update velocity
-> the current mode's maximum limits the result
-> collision and floor rules decide where the capsule can actually move

Scale Value = 1 means full input strength in the supplied direction. An analog stick at partial tilt can request less than full movement. Character Movement also has Min Analog Walk Speed, which is the low-end ground speed used for small non-zero analog input. None of those input values raise the configured maximum.

That is why this is the wrong sprint graph:

Sprint pressed
-> Add Movement Input with Scale Value = 2

It changes the request, not the owning movement limit. With full keyboard input the request was already full strength, so the Character still obeys the same Max Walk Speed.

The pattern everyone actually uses

Give speed one owner. Store the inputs to the calculation, then calculate the component property in one place.

Start with these variables on the Character or a reusable movement-state component:

Variable Example Meaning
BaseWalkSpeed 500 The design speed before temporary modifiers.
SprintMultiplier 1.5 The multiplier used when sprint is accepted.
bWantsToSprint false The player's current request.
bCanSprint true Gameplay permission after stamina, weapon, status, and mode checks.
SlowMultiplier 1.0 The combined active slow, where 0.6 means 60% speed.
BuffMultiplier 1.0 The combined active speed buffs.
MinAllowedWalkSpeed 0 The lower clamp. Zero permits a full speed lock; use a positive value if the project forbids tiny speeds.
MaxAllowedWalkSpeed 1200 A project rule that caps stacked bonuses.

Then make one function:

pseudocode for a Blueprint function - not engine source

RecalculateMovementSpeed():
    sprintFactor = (bWantsToSprint AND bCanSprint) ? SprintMultiplier : 1.0

    effective = BaseWalkSpeed
              * sprintFactor
              * SlowMultiplier
              * BuffMultiplier

    effective = Clamp(effective, MinAllowedWalkSpeed, MaxAllowedWalkSpeed)
    CharacterMovement.MaxWalkSpeed = effective

Call that function whenever any input changes:

IA_Sprint Started
-> set bWantsToSprint = true
-> RecalculateMovementSpeed

IA_Sprint Completed or Canceled
-> set bWantsToSprint = false
-> RecalculateMovementSpeed

slow added, removed, or refreshed
-> rebuild SlowMultiplier from active effects
-> RecalculateMovementSpeed

stamina reaches zero, weapon state changes, or movement mode changes
-> update bCanSprint
-> RecalculateMovementSpeed

Use Started plus Completed/Canceled for a held Enhanced Input action. Triggered can run every update while held; repeatedly writing the same value is usually unnecessary and makes debugging noisy.

Why restoring a cached float breaks

Consider this sequence:

normal speed = 500
sprint pressed -> cache 500, set 750
mud slow begins -> set 300
sprint released -> restore cached 500

The release silently erased the mud slow. Reversing the event order can erase a buff instead. The bug is not event timing; it is that several systems are using one mutable float as both state and result.

With recomputation, sprint release changes only bWantsToSprint. The still active slow remains an input, so the effective value stays slowed.

More than one slow or buff

A single SlowMultiplier is enough only if one effect can exist at a time. When effects can overlap, keep an array, map, Gameplay Tag-driven state, or another explicit collection of active modifiers. Rebuild the combined value when the collection changes.

Decide the stacking rule as game design:

  • multiplying 0.8 * 0.5 produces a 40% final factor;
  • choosing the strongest slow would produce 0.5 instead;
  • adding percentages needs an explicit lower and upper clamp.

There is no universally correct formula. The important invariant is that the formula lives in one function and every system contributes data rather than writing Max Walk Speed independently.

Crouch and movement mode are separate inputs

Character Movement selects Max Walk Speed Crouched while crouched. Changing Max Walk Speed alone does not automatically change that property.

Choose a deliberate policy:

  • use a separately authored BaseCrouchedSpeed and apply the same global slow/buff factors to Max Walk Speed Crouched;
  • disable sprint permission while crouched; or
  • allow a distinct crouch-sprint multiplier if the game calls for it.

Do not copy the current standing Max Walk Speed into Max Walk Speed Crouched every update. That erases the reason the two settings exist.

Swimming, flying, and custom modes also have separate maximums. If a shared status effect should slow all movement, let one state owner calculate every affected mode-specific maximum. If the effect is "mud slows walking," change only the ground calculation.

What changing Max Walk Speed does not do

Writing the property:

  • does not move the Character by itself;
  • does not create movement input;
  • does not instantly make actual velocity equal the new maximum;
  • does not bypass collision, floor checks, movement mode, root motion, or an ignored input gate;
  • does not change Max Walk Speed Crouched, Max Swim Speed, Max Fly Speed, or a custom mode's logic;
  • does not choose a run animation;
  • does not consume stamina; and
  • does not automatically replicate your sprint/slow/buff rules.

The Blueprint property setter has no Boolean success output. On a valid Character's built-in Character Movement component, it writes the float. If you reached the node through an invalid Character or component reference, Blueprint reports an Accessed None-style runtime error and skips useful work. Guard external references; inside the Character Blueprint, use its built-in component directly.

Multiplayer: synchronize the reason, not only the float

Character Movement predicts the owning player's motion and the server checks that motion. The server must therefore use the accepted sprint and modifier state when it reproduces moves.

For a beginner Blueprint implementation:

owning client starts or stops sprint
-> Server_SetWantsToSprint(requested state)

server validates stamina, status, and game rules
-> writes replicated sprint/effect state
-> calls RecalculateMovementSpeed on the server

RepNotify on clients
-> calls the same RecalculateMovementSpeed

The server should validate rather than accept an arbitrary speed float from the client. Replicate bIsSprinting, a validated effective speed, or the small set of authoritative modifiers your game needs. Which representation is best depends on whether other systems need to understand why the speed changed.

Max Walk Speed itself is not a general-purpose replicated property. Setting it only on the owning client lets prediction use a value the server may reject, causing corrections. Setting it only on the server can leave the owning client predicting with an old value until your state reaches it. Apply the same authoritative result on every copy that simulates or presents the Character; advanced projects can predict the local sprint request and roll it back if the server rejects it.

Built-in Character Movement already transports and corrects normal movement. That does not make arbitrary new Blueprint state part of its saved-move protocol. A deeply predicted custom sprint or ability system may need a custom Character Movement implementation, but a server-validated replicated state is the honest beginner boundary.

Animation reads the result

An Animation Blueprint usually wants motion, not permission:

OwnerCharacter
-> Get Velocity
-> Vector Length XY
-> GroundSpeed

Why not read Max Walk Speed?

  • the Character may still be accelerating;
  • collision may block it;
  • it may be braking or sliding;
  • analog input may request less than full speed;
  • it may be falling, on a moving base, or under root motion; and
  • the maximum can change before velocity catches up.

Use actual velocity for locomotion blend spaces. Read replicated gameplay state such as bIsSprinting only when the animation needs the intent as well, for example a sprint-start pose that should begin before full speed is reached.

A practical debugging ladder

When sprint or a slow "does nothing," inspect in this order:

  1. Input request: Does the sprint action fire on the intended local player?
  2. State inputs: What are bWantsToSprint, bCanSprint, and every active multiplier on this Character instance?
  3. Calculated result: Put one breakpoint in RecalculateMovementSpeed. Which value did it produce?
  4. Component value: Read Max Walk Speed immediately after the function. Did another graph overwrite it later?
  5. Movement mode and crouch: Is the Character using a different maximum?
  6. Actual motion: Watch Velocity and Vector Length XY. A configured cap is not proof of motion.
  7. Acceleration and braking: Is the result merely taking time to change?
  8. Collision and input gates: Is the capsule blocked, unpossessed, or ignoring movement input?
  9. Network copy: In multiplayer Play In Editor, are you watching the owning client, server, or a simulated proxy, and do their calculated values agree?

If Max Walk Speed changes and immediately changes back, search the Blueprint for every setter. Runtime initialization, crouch code, stamina code, pickups, and animation-event experiments are common competing writers.

Lookalikes - which control do I want?

Control Use it for It is not
Max Walk Speed The standing ground-speed limit. Current velocity or input strength.
Max Walk Speed Crouched The crouched ground-speed limit. A crouch request.
Max Acceleration How quickly velocity can change toward input. A maximum velocity.
Braking Deceleration Walking No-input walking slowdown. A hard stop.
Add Movement Input A per-update directional request. A sprint-speed setter.
Get Velocity The motion result used by animation and debugging. A movement limit.
Set Actor Location An intentional placement or teleport. Predicted Character walking.
Global Time Dilation / Custom Time Dilation Changing simulation time scale. A clean substitute for gameplay movement modifiers.

Going deeper