Movement System

Documentation Unreal Engine AI Movement

Tactical AI positioning with direction sampling, distance maintenance, strafing, and pawn avoidance.


Smart positioning that makes AI feel alive. Approaching, strafing, retreating, and avoiding obstacles without looking robotic.

When to Use This

  • Any AI that needs tactical positioning around a target
  • Melee enemies that maintain attack distance
  • Ranged enemies that keep their distance
  • Group AI where pawns need to avoid each other
  • Boss fights with phase-based positioning changes

This system can be used independently of the other plugin systems.


Core Concepts

Direction Sampling

Every tick, the system evaluates 16 directions around the AI and scores each one:

Interactive Direction Sampling

Move mouse to simulate Target
AI Pawn
Target
Ideal Range
Green arrows = High Score (Preferred Direction)

Each direction gets a score based on:

  • Distance to target: Does moving here get us closer to ideal range?
  • Angle to target: Are we facing the target?
  • Avoidance: Is there a wall or another pawn in this direction?
  • Positioning Rules: Custom modifiers you define

The highest-scoring direction wins. The result is movement that feels intelligent because it considers multiple factors simultaneously.

Distance Maintenance

The AI tries to stay within an ideal distance range:

Too Close    Ideal Range    Too Far
   |---------|============|---------|
   0        Min          Max       ∞
          (approach)    (hold)    (retreat)

Configure this via DesiredMinDistance and DesiredMaxDistance, or use a MovementBehaviorProfile.

Strafing

The AI naturally circles the target while maintaining distance:

  • AutoStrafeSwap: Randomly changes direction to avoid predictability
  • Strafe Fatigue: After strafing too long, the AI rests briefly
  • Threat-Triggered Swap: If the player stares at the AI, it swaps direction (requires Threat Detection)

Hybrid Navigation

The system intelligently switches between two movement modes:

ModeWhenHow
PathfindingTarget is far awayUses NavMesh for navigation
Direct InputTarget is closeDirect movement input for responsiveness

The switch happens at HybridSwitchDistance (default: 800 units). This gives you the reliability of pathfinding at range and the snappy feel of direct control up close.


Quick Setup

Option 1: Use a Preset

// In your AI Controller's BeginPlay:
MovementEvaluator->ApplyBehaviorConfig(FMovementBehaviorConfig::MakeAttacker());

Available presets:

  • MakeAttacker(): Close-range aggressive
  • MakeWaiter(): Mid-range patient
  • MakeFlanker(): Wide circling
  • MakeCoward(): Maintains distance, retreats when approached

Option 2: Use a Data Asset

  1. Create a MovementBehaviorProfile data asset
  2. Configure desired distances, strafing, and positioning rules
  3. Apply it:
MovementEvaluator->ApplyBehaviorProfile(MyProfile);

Option 3: Configure at Runtime

MovementEvaluator->SetDesiredDistance(200.f, 350.f);
MovementEvaluator->SetStrafeSide(1);  // 1 = right, -1 = left

This is the most automated way. The movement profile is determined by the AI's current combat role.

  1. Configure your EnemyAIConfig data asset.
  2. Assign profiles to roles (e.g., Attacker gets Aggressive, Waiter gets Passive).
  3. The system syncs automatically when the role changes.
// Called by EnemyControllerBase automatically
MovementEvaluator->SyncForCombatRole(CurrentRole, MyAIConfig);

Key Properties

PropertyDefaultPurpose
NumSamples16Directions to evaluate per tick
DesiredMinDistance200Closest the AI wants to be
DesiredMaxDistance400Farthest before approaching
EnableAvoidancetrueAvoid other pawns
AvoidanceRadius125How far to stay from others
EnableHybridMovementtrueSwitch between pathfinding and direct
HybridSwitchDistance800Distance to switch modes
AutoStrafeSwaptrueRandomly change strafe direction
StrafeTimeLimit5.0Seconds before fatigue rest

See Configuration Reference for the complete list.


Key Functions

// Main tick function - call from StateTree or Blueprint
EMovementEvaluatorResult EvaluateAndMove();
 
// Apply a preset configuration
void ApplyBehaviorConfig(const FMovementBehaviorConfig& Config);
 
// Apply a data asset profile
void ApplyBehaviorProfile(UMovementBehaviorProfile* Profile);
 
// Runtime adjustments
void SetDesiredDistance(float Min, float Max);
void SetStrafeSide(int Side);  // 1, -1, or 0 for auto
void SwapStrafeSide();
 
// Sync with AI Config (Role-based switch)
bool SyncForCombatRole(FGameplayTag Role, UEnemyAIConfig* Config);

Positioning Rules

For advanced control, create custom Positioning Rules. These are UObjects that modify direction scores:

UCLASS()
class UAvoidCornersRule : public UPositioningRule
{
    virtual float EvaluateDirection(const FPositioningContext& Context) override
    {
        // Return 0.0 to 1.0 multiplier
        // Lower values make this direction less desirable
    }
};

Add rules to your MovementBehaviorProfile. They stack, so all rules are evaluated and their scores are multiplied together.


Debug Tools

Console Commands:

SEC.Debug.Movement.DrawScoring 1      // Visualize direction scores
SEC.Debug.Movement.DrawAvoidance 1    // Show avoidance radii
SEC.Debug.Movement.LogStrafeState 1   // Log strafe decisions

Blueprint/C++:

MovementEvaluator->bDebugLog = true;

Integration Points

SystemHow Movement Uses It
Threat DetectionSwaps strafe direction when player stares too long
Combat RolesDifferent roles apply different MovementBehaviorProfiles
Action SystemActions can temporarily override movement (e.g., lunging)