Mover movement system
Mover is Epic's experimental replacement for UCharacterMovementComponent
(CMC). It moves any actor — not just capsule-based characters — through a
data-driven, deterministic simulation with rollback networking. Movement
logic lives in modular objects (movement modes, layered moves, transitions,
modifiers) instead of a hard-coded enum + switch, and all state flows through
replicated snapshot structs instead of direct component mutation.
Status in 5.8: Experimental (Engine/Plugins/Experimental/Mover/). APIs
still change between minor versions. CMC remains fully supported; choose Mover
for new projects that want its modular architecture, rollback netcode, or
physics-driven movement — see the ue-character-and-movement skill for CMC.
When to use this skill
- Building a player/AI pawn on
UMoverComponent/UCharacterMoverComponent. - Authoring a custom movement mode (glide, wall-run, grapple) or transition.
- Applying temporary motion: dashes, launches, knockbacks, teleports.
- Migrating a CMC character to Mover, or deciding whether to.
- Debugging "my Mover actor won't move / snaps back / ignores SetActorLocation".
Mental model (the part that prevents most mistakes)
Each simulation frame, the backend drives this loop:
ProduceInput → SimulationTick → FinalizeFrame
(author an (modes + layered (apply new state to
input cmd) moves propose & the actor's components)
execute movement)
FMoverInputCmdContext— what the player/AI wants this frame. AFMoverDataCollectionof typed structs; the default set isFCharacterDefaultInputs(MoverDataModelTypes.h:34).FMoverSyncState(MoverSimulationTypes.h:228) — the authoritative, replicated, rollback-able state: current mode name, active layered moves/modifiers, and a data collection holdingFMoverDefaultSyncState(MoverDataModelTypes.h:148— location, orientation, velocity, movement base).- The active movement mode and any layered moves each generate an
FProposedMove(MoveLibrary/MovementUtilsTypes.h); a movement mixer combines them byEMoveMixModeand priority; the mode'sSimulationTickexecutes the result against collision.
Three rules follow:
- Never mutate movement state directly. No
SetActorLocation, no velocity setters. Queue things instead:QueueNextMode,QueueLayeredMove,QueueInstantMovementEffect,QueueMovementModifier. Mover warns when an external system moves the actor (bWarnOnExternalMovement,MoverComponent.h:933). - All gameplay influence enters through the input cmd or queued objects, so the simulation can replay them identically during a network rollback.
ProduceInputruns only on the locally-controlled instance and is not re-run during resimulation — author intent there, don't simulate there.
Enabling Mover
- Enable the Mover plugin (Experimental). Optionally MoverExamples (sample pawns, modes, zipline/vault content) and MoverTests. Physics-driven movement lives in the separate ChaosMover plugin (in 5.8 the physics backend and modes moved there entirely).
- C++ module dependency:
// MyGame.Build.cs
PublicDependencyModuleNames.AddRange(new string[] { "Mover" });
// Add "NetworkPrediction" too if you touch the NP backend/liaison types directly.
Minimal Mover pawn (C++)
UCharacterMoverComponent (DefaultMovementSet/CharacterMoverComponent.h:27)
extends UMoverComponent with character defaults: Walking/Falling/Flying modes
pre-registered, StartingMovementMode = Falling, jump + stance (crouch)
handling. The plain UMoverComponent starts with no modes.
// MyMoverPawn.h
#include "GameFramework/Pawn.h"
#include "MoverSimulationTypes.h" // IMoverInputProducerInterface
#include "MyMoverPawn.generated.h"
UCLASS()
class MYGAME_API AMyMoverPawn : public APawn, public IMoverInputProducerInterface
{
GENERATED_BODY()
public:
AMyMoverPawn();
protected:
// Entry point the MoverComponent calls each sim frame on the controlling instance
virtual void ProduceInput_Implementation(int32 SimTimeMs,
FMoverInputCmdContext& InputCmdResult) override;
UPROPERTY(VisibleAnywhere, Category = Movement)
TObjectPtr<class UCharacterMoverComponent> MoverComp;
UPROPERTY(VisibleAnywhere, Category = Components)
TObjectPtr<class UCapsuleComponent> Capsule;
// Cached from Enhanced Input bindings (IA_Move / IA_Jump)
FVector CachedMoveIntent = FVector::ZeroVector;
bool bJumpJustPressed = false;
bool bJumpHeld = false;
};
// MyMoverPawn.cpp
#include "Components/CapsuleComponent.h"
#include "DefaultMovementSet/CharacterMoverComponent.h"
#include "MoverDataModelTypes.h"
AMyMoverPawn::AMyMoverPawn()
{
Capsule = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Capsule"));
Capsule->InitCapsuleSize(34.f, 88.f);
SetRootComponent(Capsule); // Mover moves the root ("updated") component
MoverComp = CreateDefaultSubobject<UCharacterMoverComponent>(TEXT("MoverComponent"));
}
void AMyMoverPawn::ProduceInput_Implementation(int32 SimTimeMs,
FMoverInputCmdContext& InputCmdResult)
{
FCharacterDefaultInputs& Inputs =
InputCmdResult.InputCollection.FindOrAddMutableDataByType<FCharacterDefaultInputs>();
FRotator ControlRot = FRotator::ZeroRotator;
if (const AController* C = GetController())
{
ControlRot = C->GetControlRotation();
}
Inputs.ControlRotation = ControlRot;
// Camera-relative directional intent, per-axis magnitude in [-1, 1]
const FVector WorldIntent =
FRotator(0.f, ControlRot.Yaw, 0.f).RotateVector(CachedMoveIntent);
Inputs.SetMoveInput(EMoveInputType::DirectionalIntent, WorldIntent);
// Face movement direction (leave zero for "no orientation change")
Inputs.OrientationIntent = WorldIntent.GetSafeNormal();
Inputs.bIsJumpJustPressed = bJumpJustPressed;
Inputs.bIsJumpPressed = bJumpHeld;
Inputs.SuggestedMovementMode = NAME_None;
bJumpJustPressed = false; // edge-triggered; consume it
}
Wiring notes:
- If the owning actor implements
IMoverInputProducerInterface, the MoverComponent auto-registers it as itsInputProducerat BeginPlay (MoverComponent.cpp:292-302). Actor components implementing the interface are also gathered whenbGatherInputFromAllInputProducerComponentsis true (MoverComponent.h:232). ProduceInputis aBlueprintNativeEvent— overrideProduceInput_Implementationin C++ or the Produce Input event in BP.- Bind Enhanced Input actions normally in
SetupPlayerInputComponent; the handlers just cache values thatProduceInputreads. SeeMoverExamplesCharacter.h/.cppfor the full reference implementation. EMoveInputType::Velocityrequests an exact velocity instead of directional intent (used by AI/nav movement). For AI pathfinding, add aUNavMoverComponent(DefaultMovementSet/NavMoverComponent.h) and feed its consumed nav data into the input cmd, asAMoverExamplesCharacterdoes.
Movement modes
Modes are instanced UBaseMovementMode objects (MovementMode.h:40) keyed by
FName in UMoverComponent::MovementModes (MoverComponent.h:209). Default
names live in DefaultModeNames (MoverSimulationTypes.h:25-31):
| Name | Default class | Notes |
|---|---|---|
Walking |
UWalkingMode (DefaultMovementSet/Modes/WalkingMode.h:34) |
ground movement, floor checks, based movement |
Falling |
UFallingMode (Modes/FallingMode.h) |
airborne + gravity; default starting mode of UCharacterMoverComponent |
Flying |
UFlyingMode (Modes/FlyingMode.h) |
free 3D movement |
Swimming |
USwimmingMode (Modes/SwimmingMode.h) |
requires Water plugin volumes; not registered by default |
| — | UNavWalkingMode, Async*Mode; Chaos*Mode (ChaosMover plugin) |
nav-mesh walking, async-sim and physics-backend variants |
Changing modes:
// From game code (applies at the start of the next sim frame):
MoverComp->QueueNextMode(DefaultModeNames::Flying); // MoverComponent.h:414
// From input (the default character modes honor this):
Inputs.SuggestedMovementMode = DefaultModeNames::Flying; // MoverDataModelTypes.h:66
// Add/remove modes at runtime:
MoverComp->AddMovementModeFromClass(TEXT("Gliding"), UMyGlidingMode::StaticClass());
MoverComp->RemoveMovementMode(TEXT("Gliding"));
React to changes via the OnMovementModeChanged delegate
(MoverComponent.h:128). Mode-owned Transitions and component-level
Transitions (MoverComponent.h:217) evaluate every tick and can switch modes
declaratively — a UBaseMovementModeTransition returns the target mode name
from Evaluate (MovementModeTransition.h:65).
Custom mode skeleton (full walkthrough in references/modes-transitions-and-modifiers.md):
UCLASS()
class UMyGlidingMode : public UBaseMovementMode
{
GENERATED_BODY()
public:
// Phase 1: propose velocity/orientation from input + current state
// (5.8 added the leading FMoverSimContext parameter)
virtual void GenerateMove_Implementation(const FMoverSimContext& SimContext,
const FMoverTickStartData& StartState, const FMoverTimeStep& TimeStep,
FProposedMove& OutProposedMove) const override;
// Phase 2: execute the mixed proposed move against the world
virtual void SimulationTick_Implementation(const FSimulationTickParams& Params,
FMoverTickEndData& OutputState) override;
};
Modes are Within = MoverComponent — create them via the MovementModes map
(editor), AddMovementModeFromClass, or CreateDefaultSubobject on a
MoverComponent subclass; never NewObject with a random outer.
Layered moves (temporary motion: dash, launch, knockback)
Layered moves (FLayeredMoveBase, LayeredMove.h:74) run on top of the
current mode for a duration, each generating a proposed move mixed by
MixMode (EMoveMixMode: additive / override velocity / override all) and
Priority. They replicate and participate in rollback.
#include "DefaultMovementSet/LayeredMoves/BasicLayeredMoves.h"
TSharedPtr<FLayeredMove_LinearVelocity> Dash = MakeShared<FLayeredMove_LinearVelocity>();
Dash->Velocity = GetActorForwardVector() * 1200.f;
Dash->DurationMs = 250.f; // 0 = single tick, <0 = until removed
Dash->MixMode = EMoveMixMode::OverrideVelocity;
MoverComp->QueueLayeredMove(Dash); // MoverComponent.h:314
Built-ins in DefaultMovementSet/LayeredMoves/BasicLayeredMoves.h:
FLayeredMove_LinearVelocity:29, FLayeredMove_JumpImpulseOverDuration:147,
FLayeredMove_JumpTo:187, FLayeredMove_MoveTo:253,
FLayeredMove_MoveToDynamic:316, FLayeredMove_RadialImpulse:353; plus
FLayeredMove_AnimRootMotion (LayeredMoves/AnimRootMotionLayeredMove.h) for
montage root motion and MultiJumpLayeredMove.h. Cancel by gameplay tag with
CancelFeaturesWithTag (MoverComponent.h:364).
5.7 added an instanced flavor — stateless ULayeredMoveLogic classes with
replicated FLayeredMoveInstancedData (LayeredMoveBase.h), registered via
RegisterMove and activated with QueueLayeredMoveActivation
(MoverComponent.h:303). Details and custom-move authoring in
references/layered-moves-and-instant-effects.md.
Instant movement effects (one-tick state changes)
FInstantMovementEffect subtypes (InstantMovementEffect.h:51) mutate the
movement state for exactly one tick — the rollback-safe replacement for
"just set the actor's location/velocity":
#include "DefaultMovementSet/InstantMovementEffects/BasicInstantMovementEffects.h"
// Teleport (instead of SetActorLocation):
TSharedPtr<FTeleportEffect> Teleport = MakeShared<FTeleportEffect>();
Teleport->TargetLocation = Destination;
MoverComp->QueueInstantMovementEffect(Teleport); // MoverComponent.h:394
// Launch (instead of LaunchCharacter / direct velocity write):
TSharedPtr<FApplyVelocityEffect> Launch = MakeShared<FApplyVelocityEffect>();
Launch->VelocityToApply = FVector(0, 0, 800);
MoverComp->QueueInstantMovementEffect(Launch);
Built-ins: FTeleportEffect:15, FJumpImpulseEffect:67,
FApplyVelocityEffect:96 (in BasicInstantMovementEffects.h). For networked
physics simulations, ScheduleInstantMovementEffect (MoverComponent.h:402)
delays application so every endpoint applies it on the same frame.
Jumping, crouching, state queries
UCharacterMoverComponent provides the classic character surface:
MoverComp->Jump(); // CharacterMoverComponent.h:87 (queues a jump impulse effect)
MoverComp->CanActorJump(); // :83
MoverComp->Crouch(); // :95 — applies an FStanceModifier (capsule resize + tag)
MoverComp->UnCrouch(); // :99
MoverComp->IsOnGround(); MoverComp->IsFalling(); MoverComp->IsAirborne();
MoverComp->IsCrouching(); MoverComp->IsSwimming(); MoverComp->IsSlopeSliding();
The default character inputs also drive jumping (bIsJumpJustPressed) when
bHandleJump is set (CharacterMoverComponent.h:129). Crouching is a
movement modifier (FStanceModifier,
DefaultMovementSet/MovementModifiers/StanceModifier.h:30) — see the modes
reference for modifier authoring.
General queries on any UMoverComponent:
FVector Vel = MoverComp->GetVelocity(); // MoverComponent.h:526
FVector Wish = MoverComp->GetMovementIntent(); // :530
FName Mode = MoverComp->GetMovementModeName(); // :548
// Full state snapshot:
const FMoverDefaultSyncState* State =
MoverComp->GetSyncState().SyncStateCollection.FindDataByType<FMoverDefaultSyncState>();
// State tags (MoverTypes.h:15-25): Mover_IsOnGround, Mover_IsInAir, Mover_IsFalling...
bool bGrounded = MoverComp->HasGameplayTag(Mover_IsOnGround, true); // MoverComponent.h:704
// Floor under the actor:
FHitResult Floor;
if (MoverComp->TryGetFloorCheckHitResult(Floor)) { /* ... */ } // :590
Prediction sampling for anim/motion matching: GetPredictedTrajectory
(MoverComponent.h:544).
Tuning speeds & shared settings
The legacy-style modes read a shared settings object,
UCommonLegacyMovementSettings
(DefaultMovementSet/Settings/CommonLegacyMovementSettings.h): MaxSpeed:63,
Acceleration:114, Deceleration:110, TurningRate:118, MaxStepHeight:59,
MaxWalkSlopeCosine:40, JumpUpwardsSpeed:133, ground/air/swim mode-name
mappings, friction and braking. Edit it under the Mover component's Shared
Settings array (auto-populated from each mode's SharedSettingsClasses), or
at runtime:
if (UCommonLegacyMovementSettings* Settings =
MoverComp->FindSharedSettings_Mutable<UCommonLegacyMovementSettings>())
{
Settings->MaxSpeed = 400.f; // e.g. walk toggle
}
Networking backends (overview)
The MoverComponent doesn't tick itself; a backend liaison
(Backends/MoverBackendLiaison.h:24, chosen by BackendClass,
MoverComponent.h:206) drives ProduceInput/SimulationTick/FinalizeFrame:
| Backend | Class | Use for |
|---|---|---|
| Network Prediction (default) | UMoverNetworkPredictionLiaisonComponent (Backends/MoverNetworkPredictionLiaison.h:29) |
kinematic characters with client prediction + rollback |
| Chaos networked physics | UChaosMoverBackendComponent (ChaosMover plugin, ChaosMover/Backends/ChaosMoverBackend.h:28) |
physics-driven movement (UChaosCharacterMoverComponent + Chaos* modes) |
| Standalone | UMoverStandaloneLiaisonComponent (Backends/MoverStandaloneLiaison.h:100) |
single-player / no networking, lowest overhead |
Rollbacks re-simulate forward from a corrected state; OnPostSimulationRollback
(MoverComponent.h:124) fires so gameplay/VFX can react. Custom replicated
movement state = your own FMoverDataStructBase (MoverTypes.h:203) added to
the input/sync collections (the Mover analog of CMC's FSavedMove flags). Full
detail — backend setup, custom state data, smoothing, reconciliation — in
references/networking-and-backends.md.
CMC → Mover migration cheat sheet
| CMC | Mover |
|---|---|
MaxWalkSpeed |
UCommonLegacyMovementSettings::MaxSpeed |
JumpZVelocity |
UCommonLegacyMovementSettings::JumpUpwardsSpeed |
SetMovementMode(MOVE_Flying) |
QueueNextMode("Flying") or input SuggestedMovementMode |
PhysCustom + CustomMovementMode |
custom UBaseMovementMode registered under its own name |
LaunchCharacter |
FApplyVelocityEffect / FLayeredMove_LinearVelocity |
SetActorLocation / teleport |
FTeleportEffect |
| Root motion montage | FLayeredMove_AnimRootMotion |
FSavedMove_Character custom flags |
custom FMoverDataStructBase in the input cmd collection |
bOrientRotationToMovement |
author OrientationIntent in ProduceInput (see pawn example) |
IsMovingOnGround() |
IsOnGround() / Mover_IsOnGround tag |
GetCharacterMovement()->Velocity = V |
not allowed — queue an instant effect or layered move |
Gotchas
- Moving the actor externally (
SetActorLocation, physics pushes on a kinematic backend) fights the simulation — Mover logs a warning and the next finalize snaps the actor back. UseFTeleportEffect, or setbAcceptExternalMovement(MoverComponent.h:937) if an external system (e.g. a cutscene) must own the transform temporarily. UMoverComponentalone does nothing — it has no movement modes and aNAME_Nonestarting mode. UseUCharacterMoverComponentor register modes and setStartingMovementModeyourself (validation will flag this).- Mode names are FNames —
QueueNextModewith a name missing fromMovementModeslogs and is ignored. ReuseDefaultModeNamesconstants. DurationMssemantics on layered moves:> 0timed,0exactly one tick,< 0runs until removed/IsFinished— a common source of "my dash never ends".PreferredModeof a layered move applies only when the move starts, not continuously (LayeredMove.h:60-70comment). Mid-move mode changes need an instant effect orQueueNextMode.- Don't cache
GetSyncState()references across frames — it's double-buffered per tick. - Async simulation: modes/transitions with
bSupportsAsyncmay run off the game thread (MovementMode.h:121) — no actor/world access inGenerateMove/SimulationTickthere; cache via the sim blackboard (GetSimBlackboard,MoverComponent.h:594). - ProduceInput edge flags: clear "just pressed" booleans after authoring a frame, or a single press repeats on every subsequent frame.
- 5.6+ renames:
OnActivate/OnDeactivate/OnGenerateMove/OnSimulationTickare dead (MovementMode.h:136-143); overrideActivate/Deactivateand the_Implementationvariants instead. Expect further churn while Experimental — pin exact signatures against your engine's headers. - Swimming needs the Water plugin and a registered
Swimmingmode;UCharacterMoverComponentdoes not register one by default.
Version notes
- Mover ships as Experimental in 5.3+ and remains Experimental in 5.8; Epic states CMC stays supported for the foreseeable future.
- 5.7 added the instanced layered-move system (
ULayeredMoveLogic), the rollback-aware blackboard, and pathed physics movement. - 5.8 moved physics-driven movement out of the Mover plugin into the
ChaosMover plugin (
UChaosMoverBackendComponent,Chaos*Modeclasses,ChaosMover/PathedMovement/), replacing the 5.7MoverNetworkPhysicsLiaison*backends andPhysicsDriven*modes.GenerateMovealso gained a leadingFMoverSimContextparameter. - Line numbers in plugin headers drift across releases; header paths and class/function names are stable.
References & source material
Plugin source (UE 5.8, Engine/Plugins/Experimental/Mover/Source/Mover/Public/):
MoverComponent.h—UMoverComponent:93,OnMovementModeChanged:128,ProduceInput:186,FinalizeFrame:189,BackendClass:206,MovementModes:209,StartingMovementMode:213,Transitions:217,InputProducer:228,QueueLayeredMove:314,QueueMovementModifier:352,CancelFeaturesWithTag:364,QueueInstantMovementEffect:394,QueueNextMode:414,SetGravityOverride:431,GetVelocity:526,GetPredictedTrajectory:544,GetMovementModeName:548,GetSyncState:573,TryGetFloorCheckHitResult:590,GetSimBlackboard:594,HasGameplayTag:704,bWarnOnExternalMovement:933,bAcceptExternalMovement:937.MovementMode.h—UBaseMovementMode:40,GenerateMove:60,SimulationTick:63,SharedSettingsClasses:106,Transitions:110,GameplayTags:114,bSupportsAsync:121.MovementModeTransition.h—FTransitionEvalResult:18,UBaseMovementModeTransition:38,Evaluate:65,Trigger:68.MoverSimulationTypes.h—DefaultModeNames:25,CommonBlackboard:34,FMoverInputCmdContext:189,FMoverSyncState:228,FMoverTickStartData:394,FSimulationTickParams:478,IMoverInputProducerInterface:517.MoverDataModelTypes.h—EMoveInputType:17,FCharacterDefaultInputs:34,FMoverDefaultSyncState:148,UMoverDataModelBlueprintLibrary:271.MoverTypes.h— state gameplay tags:15-25,FMoverTimeStep:149,FMoverDataStructBase:203,FMoverDataCollection:278,FMoverDataPersistence:442.LayeredMove.h—FLayeredMoveBase:74,FLayeredMoveGroup:191;LayeredMoveBase.h—ULayeredMoveLogic:133.InstantMovementEffect.h—FInstantMovementEffect:51.DefaultMovementSet/CharacterMoverComponent.h—UCharacterMoverComponent:27,Jump:87,Crouch:95.DefaultMovementSet/Settings/CommonLegacyMovementSettings.h—UCommonLegacyMovementSettings:13.DefaultMovementSet/LayeredMoves/BasicLayeredMoves.h,DefaultMovementSet/InstantMovementEffects/BasicInstantMovementEffects.h.Backends/MoverBackendLiaison.h:24,Backends/MoverNetworkPredictionLiaison.h:29,Backends/MoverStandaloneLiaison.h:100; Chaos physics backend:Engine/Plugins/Experimental/ChaosMover/Source/ChaosMover/Public/ChaosMover/Backends/ChaosMoverBackend.h:28.
Example source (UE 5.8):
Engine/Plugins/Experimental/MoverExamples/Source/MoverExamples/Public/MoverExamplesCharacter.h— reference input-producing pawn (Enhanced Input →FCharacterDefaultInputs).
Official docs (UE 5.8):
- Mover overview — https://dev.epicgames.com/documentation/unreal-engine/mover-in-unreal-engine
- Mover features & concepts — https://dev.epicgames.com/documentation/unreal-engine/mover-features-and-concepts-in-unreal-engine
- Comparing Mover and CMC — https://dev.epicgames.com/documentation/unreal-engine/comparing-mover-and-character-movement-component-in-unreal-engine
Deep-dive references in this skill:
- references/modes-transitions-and-modifiers.md — authoring custom movement modes, transitions, movement modifiers, turn generators, shared settings.
- references/layered-moves-and-instant-effects.md — built-in catalog, custom layered moves & instant effects, mixing rules, the instanced layered-move system (added in 5.7).
- references/networking-and-backends.md — backend liaisons, rollback flow, custom sync/input state data, smoothing, physics-driven movement.
Related skill: ue-character-and-movement covers ACharacter +
UCharacterMovementComponent, including when to prefer CMC over Mover.