Extension Modules
These components extend OmniWalk beyond its locomotion core. Each is independently optional —
add only what your game requires. All modules follow the same attach-and-configure pattern
as UOmniWalkPro.
Volume actor that overrides gravity with a priority system. Supports fixed, attract, repulse, and spline-linked modes.
Gravity follows the nearest point on a spline. For tubes, half-pipes, and winding corridors.
Propagates the character's gravity to nearby physics objects. Crates and debris fall your "down".
Maps physical materials to adhesion, friction, and speed presets. Drives footstep routing too.
Freeze surface detection and animate gravity to any direction during cutscenes. Sequencer-friendly.
Spline-defined patrol routes for AI pawns. Loop, ping-pong, and once modes. NavMesh-aware.
UOmniWalkPro to be on the same actor. Add them
alongside it in the actor's component list. No additional module dependencies are needed.
Trigger Zones
AOmniWalkTriggerZone overrides OmniWalk gravity for characters that enter a volume.
Unlike AOmniWalkGravityVolume (which affects all OmniWalk characters in range),
Trigger Zones support per-actor targeting, four gravity modes, and a priority system that resolves
conflicts when multiple zones overlap.
Fixed
Gravity pulls in a fixed world direction. Use for artificial gravity corridors, rotating space stations, or puzzle rooms that flip "down".
Point Attract
Gravity pulls toward the zone's center. Mini-planets, portals, or singularity mechanics.
Point Repulse
Gravity pushes away from the center. Anti-gravity emitters, repulsor fields, interior-of-sphere traversal.
Spline Linked
Delegates gravity computation to a referenced AOmniWalkSplineVolume. Use to combine a custom bounding shape with tube-gravity logic.
Setup
- Place an
AOmniWalkTriggerZoneactor in the level. - Set GravityMode in the Details panel. The relevant sub-property (e.g.
FixedGravityDirection) becomes active. - Resize the
CollisionShapecomponent to match your zone boundary. - Raise Priority above any overlapping
AOmniWalkGravityVolume(which is effectively priority 0). Default is 10. - Choose TargetMode — All, Tag Based, or Specific Actors.
Priority Resolution
When multiple zones overlap, UOmniWalkZonePrioritySubsystem selects the one with the highest
Priority value. Tie-breaking is first-registered. A character exiting a high-priority zone
automatically falls back to the next registered zone, then to the base AOmniWalkGravityVolume.
Priority Stack Example
Properties
| Property | Purpose | Default |
|---|---|---|
| GravityMode | Fixed / PointAttract / PointRepulse / SplineLinked | Fixed |
| FixedGravityDirection | World direction when GravityMode is Fixed | (0,0,-1) |
| Priority | Higher wins over overlapping zones | 10 |
| TargetMode | AllOmniWalkCharacters / TagBased / SpecificActors | All |
| TargetTags | GameplayTag filter (TagBased mode). Matches Actor.Tags by exact name. | — |
| TargetActors | Explicit actor list (SpecificActors mode) | — |
| LinkedSplineVolume | Spline to delegate to (SplineLinked mode) | — |
| bZoneEnabled | Runtime on/off toggle | true |
Delegates & API
// Respond to zone entry/exit
TriggerZone->OnActorEnterZone.AddDynamic(this, &AMyActor::HandleEnter);
TriggerZone->OnActorLeaveZone.AddDynamic(this, &AMyActor::HandleLeave);
// Toggle zone at runtime
TriggerZone->SetEnabled(false);
// Query gravity "up" for a world location (useful for preview/AI)
FVector GravUp = TriggerZone->ComputeGravityUpForLocation(MyPawn->GetActorLocation());
Spline Volume
AOmniWalkSplineVolume makes gravity follow the nearest point on a USplineComponent.
Characters inside the influence box have gravity pulled toward (or away from) the spline axis,
blending in at BlendRadius for smooth entry and exit.
bGravityPointsInward = true
bGravityPointsInward = false
Setup
- Place
AOmniWalkSplineVolumein the level. - Edit the Spline component to trace your tube center line.
- Resize InfluenceVolume (a Box component) to encompass the playable area.
- Set
bGravityPointsInwardto match your geometry (outside = true, inside = false). - Tune
BlendRadiusto set the blend-in distance from the spline edge.
Properties
| Property | Purpose | Default |
|---|---|---|
| BlendRadius | Distance from spline where gravity blends in (cm) | 200 |
| GravityStrength | Force magnitude applied to characters (cm/s²) | 980 |
| bGravityPointsInward | true = outside tube, false = inside tube | true |
| Priority | Priority vs other gravity volumes | 5 |
// SplineLinked: a TriggerZone delegates to this volume
TriggerZone->GravityMode = EOmniWalkTriggerGravityMode::SplineLinked;
TriggerZone->LinkedSplineVolume = MySplineVolume;
// Query gravity direction at any world point (C++ / AI use)
FVector Up = MySplineVolume->GetGravityUpForLocation(WorldPos);
Zone Priority System
UOmniWalkZonePrioritySubsystem is an automatic game subsystem — no setup required.
It maintains a runtime registry of all active AOmniWalkTriggerZone actors and resolves
which zone applies to each character when overlaps conflict.
AOmniWalkGravityVolumeis effectively priority 0.- Any
AOmniWalkTriggerZonewithPriority > 0overrides it. - When the winning zone is disabled via
SetEnabled(false), the subsystem immediately promotes the next-highest zone for all affected actors. - The subsystem is accessible via
GetGameInstance()->GetSubsystem<UOmniWalkZonePrioritySubsystem>()if you need to query it in C++.
Physics Field
UOmniWalkPhysicsField makes nearby physics-simulating objects fall in the same direction
as the character's current gravity. Add it alongside UOmniWalkPro on the character.
Each tick, it finds objects within FieldRadius and applies AddForce in the
character's "down" direction.
Field Radius Visualized
Setup
Add UOmniWalkPhysicsField to the same character Blueprint (or C++ class) that has
UOmniWalkPro. No configuration beyond FieldRadius is required for basic use.
The component self-caches UOmniWalkPro at BeginPlay.
Properties
| Property | Purpose | Default |
|---|---|---|
| FieldRadius | Sphere radius for object search (cm) | 500 |
| GravityStrength | Force magnitude (cm/s²). Match to world gravity for realism. | 980 |
| TickInterval | Update rate (seconds). Increase for better performance. | 0.05 |
| MaxAffectedObjects | Max objects per update. Prevents spikes. | 20 |
| AffectedTags | Only affect actors with these tags. Empty = all physics actors. | — |
| ExcludedTags | Never affect actors with these tags. Takes precedence. | — |
| bDebugVisualization | Draw cyan sphere in PIE showing field radius. | false |
API
UOmniWalkPhysicsField* Field = FindComponentByClass<UOmniWalkPhysicsField>();
// Disable field temporarily (e.g. during zero-g sequence)
Field->SetFieldEnabled(false);
// Resize at runtime (e.g. power-up expands field)
Field->SetFieldRadius(1200.0f);
// Enumerate currently affected actors
TArray<AActor*> Affected = Field->GetAffectedActors();
// Listen for objects entering/leaving the field
Field->OnObjectEnterField.AddDynamic(this, &AMyClass::OnObjectEntered);
Field->OnObjectLeaveField.AddDynamic(this, &AMyClass::OnObjectLeft);
Surface Response
The Surface Response system maps Unreal Physical Materials to OmniWalk behavior modifiers.
It has two parts: a data asset (UOmniWalkSurfaceResponseTable) that
defines presets, and a component (UOmniWalkSurfaceResponse) that samples
the surface underfoot each tick and applies the matching preset.
Step 1 — Create the Data Asset
- In the Content Browser: right-click → Miscellaneous → Data Asset.
- Choose
OmniWalkSurfaceResponseTableas the class. - Open the asset and add rows to the Entries array. Assign a Physical Material to each row.
- Leave
Materialas None on one entry to serve as the fallback (matched when no material is found).
Built-in Presets (C++ only)
Five named presets are available as static factory methods to populate entries programmatically:
| Preset | Adhesion | Friction | Speed | Alignment |
|---|---|---|---|---|
| MakeIcePreset() | ×0.6 | ×0.1 | ×1.2 | ×2.0 |
| MakeMagneticPreset() | ×3.0 | ×1.5 | ×0.8 | ×0.5 |
| MakeRubberPreset() | ×1.2 | ×3.0 | ×0.9 | ×1.0 |
| MakeStickyPreset() | ×5.0 | ×10.0 | ×0.4 | ×1.0 |
| MakeZeroGPreset() | ×0.0 | ×0.0 | ×1.5 | ×1.0 |
Step 2 — Add the Component
Add UOmniWalkSurfaceResponse alongside UOmniWalkPro on your character.
Assign the data asset to ResponseTable. The component auto-binds to UOmniWalkPro's
OnSurfaceAttached / OnSurfaceDetached events and resets multipliers automatically when off-surface.
// C++ constructor example
UOmniWalkSurfaceResponse* SR = CreateDefaultSubobject<UOmniWalkSurfaceResponse>(TEXT("SurfaceResponse"));
SR->ResponseTable = MyTableAsset; // UOmniWalkSurfaceResponseTable*
SR->SampleInterval = 0.1f; // Re-sample every 100 ms
FOmniWalkSurfaceEntry Fields
| Field | Effect | Default |
|---|---|---|
| Material | Physical Material to match. None = fallback. | None |
| AdhesionMultiplier | Scales UOmniWalkPro::AdhesionForce | 1.0 |
| FrictionMultiplier | Scales CMC GroundFriction | 1.0 |
| AlignmentSpeedMultiplier | Scales UOmniWalkPro::AlignmentSpeed | 1.0 |
| WalkSpeedMultiplier | Scales CMC MaxWalkSpeed | 1.0 |
| SurfaceTag | FName broadcast via OnSurfaceTypeChanged. Use for footstep routing. | None |
| FootstepSound | Optional sound asset. Retrieve from the tag callback. | None |
Footstep Routing
Bind OnSurfaceTypeChanged in Blueprint or C++ to drive footstep audio, VFX, or any per-surface logic:
// C++ bind
SurfaceResponse->OnSurfaceTypeChanged.AddDynamic(this, &AMyChar::OnSurfaceChanged);
void AMyChar::OnSurfaceChanged(FName SurfaceTag)
{
if (SurfaceTag == "Ice")
{
// play ice footstep, spawn frost VFX
}
else if (SurfaceTag == NAME_None)
{
// off surface or unmatched material — reset to default
}
}
UOmniWalkSurfaceResponse Properties
| Property | Purpose | Default |
|---|---|---|
| ResponseTable | The data asset to look up entries from | None |
| SampleInterval | Seconds between re-samples. 0 = every tick. | 0.1 |
| SampleChannel | Collision channel for underfoot trace | WorldStatic |
| SampleDistance | Trace half-length below actor origin (cm) | 200 |
Cinematic Control
UOmniWalkCinematic is designed for cutscenes and scripted sequences. It can freeze
UOmniWalkPro's surface detection — preventing unexpected gravity changes during a
camera animation — and smoothly interpolate gravity to any target direction over a configurable duration.
Cinematic Timeline
Typical Usage
UOmniWalkCinematic* Cin = FindComponentByClass<UOmniWalkCinematic>();
// --- Cutscene begins ---
Cin->SetCinematicMode(true);
// Smoothly flip gravity over 2 seconds (ease-in-out)
Cin->SetCinematicGravityDirection(FVector(0, 0, -1), 2.0f);
// Listen for completion
Cin->OnGravityTransitionComplete.AddDynamic(this, &AMyClass::OnFlipDone);
// --- Cutscene ends (call when sequence finishes) ---
Cin->SetCinematicMode(false);
One-Shot Helper
Set bAutoExitCinematicOnTransitionEnd = true to have the component automatically call
SetCinematicMode(false) once the gravity transition completes. Useful for a simple
"flip and resume" pattern without manually tracking the cutscene state.
// Auto-exit after flip completes — no manual SetCinematicMode(false) needed
Cin->bAutoExitCinematicOnTransitionEnd = true;
Cin->SetCinematicGravityDirection(FVector(0, 1, 0), 1.5f);
Properties & API Reference
| Member | Type | Notes |
|---|---|---|
| SetCinematicMode(bool) | Method | Freeze/unfreeze OmniWalkPro surface detection. |
| IsInCinematicMode() | Query | Returns current cinematic state. |
| SetCinematicGravityDirection(TargetUp, Duration, bImmediate) | Method | Begin smooth gravity transition. Duration 0 = instant snap. |
| SnapCinematicGravity(TargetUp) | Method | Instant gravity snap. Convenience wrapper. |
| CancelGravityTransition() | Method | Stop in-progress transition; hold current direction. |
| GetTransitionProgress() | Query (0..1) | Returns 1.0 when idle or complete. |
| bAutoExitCinematicOnTransitionEnd | Property | Auto-call SetCinematicMode(false) after transition. |
| bUseSmoothStep | Property | true = ease-in-out (default), false = linear. |
| OnCinematicModeChanged | Delegate | Broadcast on every SetCinematicMode call. |
| OnGravityTransitionComplete | Delegate | Broadcast when animation finishes or snaps. |
SetCinematicMode and
SetCinematicGravityDirection to Sequencer Event Track callbacks to drive gravity transitions
directly from a Level Sequence timeline without any Blueprint boilerplate.
Patrol Path
AOmniWalkPatrolPath defines an ordered sequence of world-space waypoints using a
USplineComponent. Each spline control point is a waypoint. Place this actor in the level,
edit the spline, and assign it to UOmniWalkAIPatrol on your AI pawn.
Loop
After the last point, wrap back to the first. Spline is rendered as a closed loop. Best for patrol circuits.
Ping-Pong
After the last point, the AI reverses direction back to the first. Useful for guards patrolling a hallway.
Once
Stop at the last waypoint and fire OnPatrolPathComplete. Use for escort or one-time scripted movement.
Properties
| Property | Purpose | Default |
|---|---|---|
| LoopMode | Loop / PingPong / Once | Loop |
| WaypointHeightOffset | Offset waypoints along the spline up-vector (cm). Use to lift points above curved geometry. | 0 |
| bDebugVisualization | Draw path and waypoint spheres during PIE | true |
| DebugPathColor | Color of debug lines and spheres | Cyan |
Query API
// Number of control points / waypoints
int32 N = PatrolPath->GetPatrolPointCount();
// World location of waypoint i (applies WaypointHeightOffset)
FVector Loc = PatrolPath->GetPatrolPointLocation(i);
// World transform (includes spline orientation at that point)
FTransform T = PatrolPath->GetPatrolPointTransform(i);
// Next index given current index and direction (+1 / -1)
// bReversed is set true when PingPong mode flips the direction
bool bReversed;
int32 Next = PatrolPath->GetNextPointIndex(Current, 1, bReversed);
// Returns -1 in Once mode when the end is reached
// Find the waypoint closest to an actor's position
int32 Nearest = PatrolPath->GetNearestPointIndex(MyPawn->GetActorLocation());
AI Patrol
UOmniWalkAIPatrol drives an AI pawn along an AOmniWalkPatrolPath using the
pawn's AAIController. It issues MoveToLocation requests for each waypoint in sequence,
waits for the controller's path-following result, optionally idles at each stop via
WaypointWaitTime, then advances to the next point.
Patrol Loop
Setup
- Place an
AOmniWalkPatrolPathactor and shape the spline. Set theLoopMode. - On your AI character Blueprint, add
UOmniWalkAIPatrolas a component. - Set
PatrolPathto point at the path actor. - Ensure the character has an
AAIControllerand a Nav Mesh Bounds Volume covers the patrol area. - Enable
bAutoStartOnBeginPlay(default) or callStartPatrol()manually.
The standard UE Nav Mesh is world-axis-aligned. For AI patrolling on walls or ceilings,
place a Nav Mesh Bounds Volume that encompasses the patrol area and enable
Project Down on it, or use the Recast Nav Mesh's AgentMaxStepHeight to
allow traversal of steep geometry. For fully off-axis surfaces (e.g. a vertical wall), consider
calling AddMovementInput directly from a custom AI task instead of navmesh pathing.
Properties
| Property | Purpose | Default |
|---|---|---|
| PatrolPath | The AOmniWalkPatrolPath actor to follow | None |
| bOverrideLoopMode | When true, LoopModeOverride takes precedence over the path's own mode | false |
| LoopModeOverride | Override value (active when bOverrideLoopMode = true) | Loop |
| AcceptanceRadius | Distance to consider a waypoint "reached" (cm) | 50 |
| StartWaypointIndex | First waypoint index. -1 = nearest to actor position. | 0 |
| WaypointWaitTime | Idle seconds at each waypoint before advancing | 0.5 |
| bAutoStartOnBeginPlay | Automatically begin patrol one frame after BeginPlay | true |
Control API
UOmniWalkAIPatrol* Patrol = FindComponentByClass<UOmniWalkAIPatrol>();
// Start / resume patrol
Patrol->StartPatrol();
// Pause at current position (in-flight move finishes naturally)
Patrol->PausePatrol();
Patrol->ResumePatrol();
// Full stop (aborts in-flight move)
Patrol->StopPatrol();
// Hot-swap path at runtime
Patrol->SetPatrolPath(NewPathActor);
// Teleport logic: jump to a specific waypoint index
Patrol->JumpToWaypoint(3);
// State queries
bool bActive = Patrol->IsPatrolling();
int32 Current = Patrol->GetCurrentWaypointIndex();
Events
// Fires each time a waypoint is reached
Patrol->OnReachedPatrolPoint.AddDynamic(this, &AMyClass::OnWaypointReached);
// Fires when a Once-mode path ends at the last point
Patrol->OnPatrolPathComplete.AddDynamic(this, &AMyClass::OnPatrolDone);
void AMyClass::OnWaypointReached(int32 PointIndex)
{
// e.g. play an animation, trigger dialogue, update AI state
UE_LOG(LogTemp, Log, TEXT("AI reached waypoint %d"), PointIndex);
}
Support & Legal
Troubleshooting Modules
Gravity Zones Not Applying
Symptom: Character enters a Trigger Zone or Spline Volume but gravity doesn't change.
- Check Priority: It must be higher than the base
AOmniWalkGravityVolume(Priority 0). Overlapping zones require explicit priority sorting. - Check Targeting: If using
TagBasedorSpecificActorsTargetMode, ensure the character meets the criteria. - Verify Collision: The actor must generate overlap events with the zone's collision shape.
Physics Field Not Affecting Objects
Symptom: Nearby crates or debris ignore the character's gravity.
- Ensure the objects have Simulate Physics enabled.
- Check Tags: If
AffectedTagsis not empty, the object must have one of those tags. Ensure it's not inExcludedTags. - Enable
bDebugVisualizationon the Physics Field to visually confirm the objects are inside theFieldRadius.
Surface Response Failing
Symptom: Footstep sounds or adhesion multipliers are not updating when walking on new surfaces.
- Verify the floor mesh has a valid Physical Material assigned in its collision settings.
- Ensure the
SampleChannel(default WorldStatic) correctly traces against your floor geometry. - Check that your
ResponseTabledata asset includes a row withMaterialset to None as a fallback.
AI Patrol Not Moving
Symptom: The AI pawn stays at its spawn location instead of following the patrol path.
- Ensure the pawn is possessed by an AAIController.
- Verify a Nav Mesh Bounds Volume covers the path. Press 'P' in the viewport to visualize the nav mesh.
- For steep or off-axis surfaces, check that the Nav Mesh projects correctly or use
AgentMaxStepHeight. - Confirm
PatrolPathis set in theUOmniWalkAIPatrolcomponent.
Cinematic Transitions Interrupting
Symptom: The character detaches or jerks around during a scripted gravity sequence.
- Always call
SetCinematicMode(true)before initiating the transition to suppress OmniWalk's standard surface detection logic.
About
GregOrigin
Created by Andras Gregori @ Gregorigin, a single dad currently based outside Budapest, HU.
"Building tools that empower creators to shape worlds."