Appearance
Motion 2.0 Preview 3
DANGER
IMPORTANT: Motion 2.0 Preview 3 is a complete architectural redesign and cannot be used to upgrade existing projects from ANY previous version (including Preview 1 & 2).
This is a breaking change that requires a fresh integration. However, the new architecture makes future updates much simpler.
Breaking Changes
MotionPlayerState Removed
Preview 3 removes AMotionPlayerState entirely. Motion now works with ANY PlayerState that implements IAbilitySystemInterface.
What Changed
AMotionPlayerStateclass has been deleted- Motion components now discover the ASC through the standard UE5
IAbilitySystemInterface - Event-driven initialization via
APawn::ReceiveControllerChangedDelegatewith fallback retry timers for multiplayer scenarios where PlayerState replication is delayed - Attributes are discovered by name (e.g., "WalkSpeed", "Stamina") rather than requiring a specific AttributeSet class
- Create your own PlayerState with GAS support:
cpp
// MyPlayerState.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerState.h"
#include "AbilitySystemInterface.h"
#include "MyPlayerState.generated.h"
UCLASS()
class AMyPlayerState : public APlayerState, public IAbilitySystemInterface
{
GENERATED_BODY()
public:
AMyPlayerState();
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
protected:
UPROPERTY()
TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;
UPROPERTY()
TObjectPtr<UMyAttributeSet> AttributeSet;
};cpp
// MyPlayerState.cpp
#include "MyPlayerState.h"
#include "AbilitySystemComponent.h"
AMyPlayerState::AMyPlayerState()
{
AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("AbilitySystemComponent"));
AbilitySystemComponent->SetIsReplicated(true);
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);
AttributeSet = CreateDefaultSubobject<UMyAttributeSet>(TEXT("AttributeSet"));
}
UAbilitySystemComponent* AMyPlayerState::GetAbilitySystemComponent() const
{
return AbilitySystemComponent;
}- Set your GameMode to use your PlayerState:
cpp
AMyGameMode::AMyGameMode()
{
PlayerStateClass = AMyPlayerState::StaticClass();
}- Motion will automatically discover your ASC - no additional code required!
Benefits
- Use your existing PlayerState - No need for Motion-specific base classes
- Use your own AttributeSet - Motion discovers attributes by name
- Cleaner architecture - Standard UE5 patterns, no custom interfaces
- Event-driven initialization - With fallback retry timers for multiplayer edge cases
Attribute Discovery
Motion now discovers attributes by name rather than requiring UMotionAttributeSet. Your AttributeSet can have any attributes as long as the property names match what Motion components expect:
| Component | Expected Attribute Name |
|---|---|
| MotionWalkComponent | WalkSpeed |
| MotionSprintingComponent | WalkSpeed, Stamina, MaxStamina |
| MotionJumpComponent | JumpVelocity |
If an expected attribute is missing, that specific feature gracefully degrades - other Motion features continue to work.
Type Renames
The following types have been renamed for consistency with Unreal Engine conventions:
| Old Name | New Name |
|---|---|
FStructMotionCurve | FMotionCurve |
GENERATED_USTRUCT_BODY() | GENERATED_BODY() (in all structs) |
Removed Gameplay Tags
The following gameplay tags have been removed from the Motion tag hierarchy:
Motion.Input.*tags (Input binding tags)Motion.Control.*tags (Control state tags)Motion.Camera.DisableCollisiontag
If you rely on these tags, define them in your project's DefaultGameplayTags.ini.
Sound Component Restructuring
UMotionMovementSoundComponent and UMotionBreathingComponent now extend UMotionComponentBase instead of UActorComponent:
- Event-driven surface detection replaces tick-based updates
- Components participate in Motion's ASC discovery system
- Consistent initialization pattern with other Motion components
MOTION_LOG Macro Signature Change
The MOTION_LOG macro now requires the component as the first parameter:
cpp
// Preview 2
MOTION_LOG(LogMotionSprinting, Log, TEXT("Sprint started"));
// Preview 3
MOTION_LOG(this, LogMotionSprinting, Log, TEXT("Sprint started"));New Features
Universal Attribute Discovery
New helper functions in UMotionAbilitySystemHelper:
cpp
// Find any attribute by name
FGameplayAttribute Attr = UMotionAbilitySystemHelper::FindAttributeByName(ASC, "WalkSpeed");
// Get/Set attribute values by name
float Value;
UMotionAbilitySystemHelper::GetAttributeValueByName(ASC, "Stamina", Value);
UMotionAbilitySystemHelper::SetAttributeValueByName(ASC, "Stamina", 5.0f);
// Check if an attribute exists
bool bHas = UMotionAbilitySystemHelper::HasAttributeByName(ASC, "JumpVelocity");Event-Driven ASC Initialization
Motion components now bind to APawn::ReceiveControllerChangedDelegate for reliable ASC discovery. This eliminates timing issues when the controller/PlayerState isn't immediately available at BeginPlay.
Event-Bus Camera System
New decoupled camera architecture via FMotionCameraEventBus:
cpp
// Movement components broadcast events instead of direct camera manipulation
EventBus->BroadcastCurveEvent(
EMotionCameraAction::Add,
CurveIdentifier,
CurveAsset,
BlendTime
);
// Subscribe to camera events in your custom camera
EventBus->OnMotionCurveEvent.AddDynamic(this, &UMyCameraComponent::HandleCurveEvent);
EventBus->OnCameraHeightEvent.AddDynamic(this, &UMyCameraComponent::HandleHeightEvent);Benefits:
- Cleaner separation between movement and camera systems
- Blueprint-friendly delegate events
- Easy to integrate custom camera implementations
- Movement components no longer require camera references
EMotionCameraAction enum:
Add- Start a camera curve effectRemove- Stop and blend out a curve effectSetHeight- Set target camera height for crouch/stand
Context-Aware Logging
Enhanced logging infrastructure with automatic context prefixing:
cpp
// All MOTION_LOG macros now require Component as first parameter
MOTION_LOG(this, LogMotionSprinting, Log, TEXT("Sprint started"));
// Output: [SERVER][MotionSprintingComponent] Sprint started
// Output: [CLIENT][MotionSprintingComponent] Sprint startedFeatures:
GetMotionLogPrefix()auto-extracts network role and component name- Network roles:
[SERVER],[DEDICATED],[CLIENT],[SIMULATED],[STANDALONE] - Zero overhead in Shipping builds (compiled out via
#if !UE_BUILD_SHIPPING) - New
LogMotionVisualcategory for Visual Logger integration
Motion Subsystem
New UMotionSubsystem (LocalPlayerSubsystem) provides centralized component orchestration:
cpp
// Access the subsystem
UMotionSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UMotionSubsystem>(LocalPlayer);
// Query active components
TArray<UMotionComponentBase*> Components = Subsystem->GetActiveComponents();
UMotionComponentBase* WalkComp = Subsystem->GetComponentByClass(UMotionWalkComponent::StaticClass());
// Auto-grant movement abilities
Subsystem->GrantMovementAbilities(ASC);Gameplay Debugger Category
New "Motion" category in the UE5 Gameplay Debugger (' key in-game):
- Active component states (Walk, Sprint, Crouch, Jump, etc.)
- Movement speeds and stamina values
- Active GameplayEffects and GameplayTags
- Camera curve information
- Subsystem registration status
Editor Validation
Motion components now validate configuration at Blueprint compile time:
- Warns if component is not attached to an ACharacter subclass
- Validates required properties before runtime
- Clear error messages in the Output Log
UCurveVector for Camera Effects
Camera curves now use UCurveVector assets instead of inline FRuntimeVectorCurve. Benefits:
- Shareable curve assets across components
- Editor preview support
- Reduced memory footprint
- Better workflow for artists
FName Curve Identifiers
Curve identifiers switched from FString to FName for better performance in TMap lookups.
Attribute System Enhancements
Improved attribute handling with better prediction support:
- Two-phase post-attribute updates - Clamping happens before sync to prevent invalid values
- Local prediction handling -
bIsLocallyPredictingflag tracks prediction state per component - Proportional crouch speed - Speed adjusts based on capsule height ratio
ClearLocalPredictionStatehelper - Clean reset of prediction flags
cpp
// Example: Check if attribute change is from local prediction
if (bIsLocallyPredicting)
{
// Skip server-sync during prediction
return;
}New Utilities
New helper structures and functions:
FMotionStopwatch - Timing utility for performance measurement:
cpp
FMotionStopwatch Watch;
Watch.Start();
// ... expensive operation ...
float ElapsedMs = Watch.GetElapsedMilliseconds();RemoveTagEffectWithFallback - Resilient tag cleanup that handles both GameplayEffect and loose tag removal:
cpp
// Safely removes tag whether applied via GE or loose tag
UMotionAbilitySystemHelper::RemoveTagEffectWithFallback(ASC, TagToRemove, EffectHandle);Platform-relative velocity helpers:
cpp
// Get velocity relative to moving platform (for conveyor belts, elevators)
FVector RelativeVel = GetPlatformRelativeVelocity(Character);
float RelativeSpeed = GetPlatformRelativeSpeed(Character);Performance Improvements
Event-Based Updates
- Event-based surface detection (traces only on footstep, not every tick)
- Event-driven breathing component (reduced CPU usage vs tick-based)
- RPC rate limiting on all networked components
Animation System Optimizations
- Time-based throttling replaces frame-counter timing for consistent behavior across framerates
- Ground trace throttling reduces raycast frequency during locomotion
TransientUPROPERTY markers on runtime-cached pointers (prevents unnecessary serialization)
Attribute Caching
- Attribute lookup results cached for repeated queries (10-100x faster for hot paths)
IAbilitySystemInterfacechecked first in ASC lookup (fastest path for conforming classes)
Memory Optimizations
- FIFO eviction for logged actors (was clear-all, now bounded at 1000 entries)
- Optimized log levels (operational messages demoted to Verbose)
Bug Fixes
- Fixed ASC discovery timing issues in multiplayer
- Removed dependency on specific PlayerState class
- Simplified component initialization flow
- Fixed initialization timeout messages (5s warning, 10s error)
- Fixed multiplayer client ASC initialization race condition
- Fixed sprint stamina comparison (normalized vs raw values)