ue-character-movement
Use this skill when working with character movement, CharacterMovementComponent, CMC, movement modes, walking, falling, swimming, flying, custom movement, network prediction, FSavedMove, root motion, floor detection, step-up, or character physics. Also use for 'PhysWalking', 'PhysCustom', 'LaunchCha
By quodsoler · 837 installs
npx skills add quodsoler/unreal-engine-skills --skill ue-character-movement
Source repository · Upstream listing
UE Character Movement
Target engine: UE 5.8 . APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".
This skill covers UCharacterMovementComponent (CMC) and ACharacter : the movement mode pipeline, floor detection and step up, custom movement modes, client side prediction and correction, root motion, custom gravity, and the 5.8 movement base rework. Everything here ships in the Engine module — no plugin and no extra Build.cs entry beyond "Engine" . Public headers: GameFramework/CharacterMovementComponent.h (which already pulls in GameFramework/RootMotionSource.h , GameFramework/CharacterMovementReplication.h , CharacterMovementComponentAsync.h and Interfaces/MovementBaseInterface.h ), GameFramework/Character.h .
Context
Read .agents/ue project context.md if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.
Identify the area from the request and the codebase. Ask only when two plausible readings would produce different code.
Request is about… Go to
Choosing between CMC and the Mover plugin [CMC vs Mover]( cmc vs mover)
Class hierarchy, movement modes, mode transitions [CMC Architecture]( cmc architecture)
Standing on a lift, rotating platform, vehicle, physics body [Movement Base]( movement base)
Where a tick goes, PhysWalking / PhysFalling , sweeps, sliding [Movement Pipeline]( movement pipeline)
Falling through floors, step up, walkable angle, perching [Floor Detection]( floor detection)
Wall run, climb, dash, grapple, any new movement type [Custom Movement Modes]( custom movement modes)
Multiplayer desync, rubber banding, saved moves, compressed flags [Network Prediction]( network prediction)
Knockback, dashes, animation driven motion [Root Motion]( root motion)
Walking on walls/ceilings, planet gravity [Custom Gravity]( custom gravity)
AI agents, navmesh driven walking, RVO avoidance [NavMesh Walking]( navmesh walking)
Jump/crouch/launch from gameplay code [ACharacter API]( acharacter api)
Speeds, friction, braking, rotation flags [Key Properties]( key properties)
Deep templates live in [cmc extension patterns.md](references/cmc extension patterns.md); per mode internals and flow diagrams live in [movement pipeline.md](references/movement pipeline.md).
CMC vs Mover
Mover (Experimental in 5.8) is a separate plugin ( Mover , not enabled by default) built around UMoverComponent , UBaseMovementMode , FLayeredMoveBase and UCharacterMoverComponent . It is not a drop in CMC replacement.
Situation Use
Shipping title, any engine supported platform CMC
Existing ACharacter hierarchy, animation and AI already wired to CMC CMC
Networked gameplay that must be stable today CMC
Non capsule, non humanoid movers (vehicles, drones) that still want rollback networking Mover
Movement composed from data driven modes/modifiers instead of a Phys subclass Mover
Movement simulated on the physics thread with Chaos Mover ( ChaosMover )
Prototype that can absorb Experimental API churn Mover
Mover details belong to ue mover . Do not mix the two components on one pawn.
CMC Architecture
UNavMovementComponent also implements INavMovementInterface ; UCharacterMovementComponent additionally implements IRVOAvoidanceInterface and INetworkPredictionInterface , and is declared UCLASS(MinimalAPI) .
CMC is a default subobject on ACharacter ( ACharacter::CharacterMovementComponentName ). ACharacter owns the capsule, mesh and high level verbs ( Jump , Crouch , LaunchCharacter ); CMC owns simulation, floor detection and prediction.
Movement Modes
EMovementMode ( Engine/EngineTypes.h ):
Mode Meaning
MOVE None No movement processing
MOVE Walking Ground movement with floor detection and step up
MOVE NavWalking Walking driven by navmesh projection
MOVE Falling Airborne: gravity, air control, landing
MOVE Swimming Fluid movement with buoyancy
MOVE Flying Free 3D movement, no gravity
MOVE Custom User defined; dispatches to PhysCustom with a uint8 sub mode
ACharacter::OnMovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode = 0) fires after the CMC hook and broadcasts MovementModeChangedDelegate ( FMovementModeChangedSignature ). Put enter/exit logic for custom modes in the CMC override; the current sub mode is the uint8 CustomMovementMode member.
Movement Base
The movement base is the object a character stands on and moves with. In 5.8 it is no longer a UPrimitiveComponent : it is FMovementBaseInterfaceData ( Interfaces/MovementBaseInterface.h ), which holds a TWeakObjectPtr<UObject PhysicsObjectOwner plus the IPhysicsBodyInstanceOwner that supplies the base behaviour. This lets non component physics objects act as bases.
Reading the base
APawn declares GetMovementBaseObject() , GetMovementBaseInterfaceData() and GetMovementBaseInterfaceData Mutable() ; ACharacter overrides all three as final . FMovementBaseInterfaceData itself exposes IsValid() , Clear() , Set() , GetBodyInstanceOwner() , GetMovementBaseObject() and GetMovementBaseObjectOwner() .
Setting the base
Build the struct from what you already have:
MovementBaseUtility::GetMovementBaseDataFromPhysicsOwner(UObject ) does the same from a replicated PhysicsObjectOwner .
Utility namespace
Every MovementBaseUtility helper now takes FMovementBaseInterfaceData instead of UPrimitiveComponent : IsDynamicBase , IsSimulatedBase , UseRelativeLocation , AddTickDependency , RemoveTickDependency , GetMovementBaseVelocity , GetMovementBaseTangentialVelocity , GetMovementBaseTransform , TransformLocationToWorld , TransformLocationToLocal , TransformDirectionToWorld , TransformDirectionToLocal . New in 5.8: DoesMovementBaseDataMatch , IsMovementBaseDataValid , GetMovementBaseDataFromPhysicsOwner , GetMovementBaseDataFromHitResult .
Stored and replicated base state
Old member 5.8 member Holder
MovementBase MovementBaseInterfaceData FBasedMovementInfo
MovementBase PhysicsObjectOwner FRepRootMotionMontage
MovementBase MovementBasePhysicsObjectOwner FCharacterNetworkMoveData
StartBase / EndBase StartMovementBaseInterfaceData / EndMovementBaseInterfaceData FSavedMove Character
LastServerMovementBase LastMovementBaseInterfaceData UCharacterMovementComponent
Every server authority and correction virtual that used to take a UPrimitiveComponent ClientMovementBase now has an FMovementBaseInterfaceData overload: ServerMoveHandleClientError , ServerCheckClientError , ServerExceedsAllowablePositionError , ServerShouldUseAuthoritativePosition , ClientAdjustPosition Implementation , ClientVeryShortAdjustPosition Implementation , ClientAdjustRootMotionPosition Implementation , ClientAdjustRootMotionSourcePosition Implementation , OnClientCorrectionReceived (plus the non virtual RevertMove ). Override the new overload — overriding the deprecated one silently stops being called.
ACharacter::BaseChange() and ACharacter::OnRep ReplicatedBasedMovement() are the notification hooks; ACharacter::GetBasedMovement() returns the FBasedMovementInfo .
Movement Pipeline
PerformMovement(float DeltaTime) (protected) is the autonomous path entry point; simulated proxies go through SimulatedTick , which calls PerformMovement only while root motion is active and otherwise SimulateMovement (a MoveSmooth extrapolation that skips the Phys functions). PerformMovement reaches StartNewPhysics(float deltaTime, int32 Iterations) , which dispatches on MovementMode . All Phys functions are virtual ; PhysFalling is public ( CharacterMovementComponent.h:1663 ), the other five are protected ( :1995 2007 ):
Inside a Phys function:
SafeMoveUpdatedComponent wraps MoveUpdatedComponent and calls ResolvePenetration on initial overlap — always prefer it inside custom Phys code. When overriding it, add using UMovementComponent::SafeMoveUpdatedComponent; next to the declaration or the FRotator overload is hidden.
On a blocking hit, CMC's override of SlideAlongSurface(const FVector& Delta, float Time, const FVector& Normal, FHitResult& Hit, bool bHandleImpact) projects the remaining delta along the surface (and refuses to slide up unwalkable slopes while walking). Corner hits go through TwoWallAdjust(FVector& WorldSpaceDelta, const FHitResult& Hit, const FVector& OldHitNormal) const . During walking, ComputeGroundMovementDelta(const FVector& Delta, const FHitResult& RampHit, const bool bHitFromLineTrace) const reorients the delta along the ramp, and MaintainHorizontalGroundVelocity() flattens velocity afterwards (rescaling to preserve magnitude when bMaintainHorizontalGroundVelocity is false).
SetUpdatedComponent(USceneComponent NewUpdatedComponent) is overridden on CMC; it is what binds the component being moved (the capsule) and re registers ticking. Sub stepping is bounded by MaxSimulationTimeStep and MaxSimulationIterations ; MIN TICK TIME is the floor below which a slice is discarded. CMC can also run the whole simulation on the physics thread behind the CVar p.AsyncCharacterMovement (default 0 ; the engine marks it not fully developed) through FCharacterMovementComponentAsyncInput / FCharacterMovementComponentAsyncOutput / FCharacterMovementComponentAsyncCallback — custom Phys state is not mirrored into that path automatically. Full per mode breakdowns and the async plumbing: [movement pipeline.md](references/movement pipeline.md).
Floor Detection
FFindFloorResult lives in CharacterMovementComponentAsync.h ( USTRUCT(BlueprintType) ), not in the CMC header:
Member Meaning
bBlockingHit Sweep hit something, not in initial penetration
bWalkableFloor Hit surface passes the walkability test
bLineTrace Result came from the line trace fallback
FloorDist Distance from the swept capsule
LineDist Distance from the line trace (valid only if bLineTrace )
HitResult Full FHitResult
Helpers: IsWalkableFloor() ( bBlockingHit && bWalkableFloor ), GetDistanceToFloor() , Clear() , SetFromSweep() , SetFromLineTrace() .
FindFloor delegates to ComputeFloorDist (downward capsule sweep, then a line trace to validate the contact point). The cached result is CurrentFloor . AdjustFloorHeight() snaps the capsule between MIN FLOOR DIST and MAX FLOOR DIST .
Walkability: WalkableFloorAngle (degrees, clamped 0–90) and the derived WalkableFloorZ (default 0.71 , about 44.8 degrees). Set the angle through SetWalkableFloorAngle(float) — writing WalkableFloorZ directly desynchronises the pair. virtual bool IsWalkable(const FHitResult& Hit) const is the override point for per surface rules.
Step up runs through virtual bool StepUp(const FVector& GravDir, const FVector& Delta, const FHitResult& Hit, FStepDownResult OutStepDownResult = NULL) , bounded by MaxStepHeight , with PerchRadiusThreshold and PerchAdditionalHeight controlling ledge perching.
Custom Movement Modes
MOVE Custom plus the uint8 CustomMovementMode gives 256 sub modes that reuse CMC's prediction pipeline.
Call Super::PhysCustom(deltaTime, Iterations) first : the base implementation forwards to ACharacter::K2 UpdateCustomMovement(float DeltaTime) , so skipping it or calling it last breaks the Blueprint hook and any base bookkeeping added later. This skill is the authority on that ordering.
Enter and leave a mode with SetMovementMode(MOVE Custom, static cast<uint8 (EMyMovementMode::Climbing)) and SetMovementMode(MOVE Falling) . Cap speed by overriding virtual float GetMaxSpeed() const override (the