Skip to content

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

  • AMotionPlayerState class has been deleted
  • Motion components now discover the ASC through the standard UE5 IAbilitySystemInterface
  • Event-driven initialization via APawn::ReceiveControllerChangedDelegate with 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
  1. 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;
}
  1. Set your GameMode to use your PlayerState:
cpp
AMyGameMode::AMyGameMode()
{
    PlayerStateClass = AMyPlayerState::StaticClass();
}
  1. 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:

ComponentExpected Attribute Name
MotionWalkComponentWalkSpeed
MotionSprintingComponentWalkSpeed, Stamina, MaxStamina
MotionJumpComponentJumpVelocity

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 NameNew Name
FStructMotionCurveFMotionCurve
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.DisableCollision tag

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 effect
  • Remove - Stop and blend out a curve effect
  • SetHeight - 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 started

Features:

  • 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 LogMotionVisual category 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 - bIsLocallyPredicting flag tracks prediction state per component
  • Proportional crouch speed - Speed adjusts based on capsule height ratio
  • ClearLocalPredictionState helper - 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
  • Transient UPROPERTY markers on runtime-cached pointers (prevents unnecessary serialization)

Attribute Caching

  • Attribute lookup results cached for repeated queries (10-100x faster for hot paths)
  • IAbilitySystemInterface checked 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)

Motion - Advanced First Person Character Controller