Reference Devices compiles

prop_mover_device: Moving Platforms, Traps, and Sliding Doors

The `prop_mover_device` lets you animate any building piece or terrain prop along a path — think sliding doors, moving platforms, pendulum traps, or patrol hazards. From Verse you can start and stop the motion, flip its direction, dial in speed and distance at runtime, and react when the prop crushes a player, hits an NPC, or reaches its destination.

Updated Examples verified on the live UEFN compiler
Watch the Knotprop_mover_device in ~90 seconds.

Overview

The prop_mover_device is the engine behind every moving platform, sliding gate, and swinging hazard in UEFN. You place it in the scene, attach it to a prop (configured in the device's editor properties), and then drive it entirely from Verse.

When to reach for it:

  • A vault door that slides open when a player solves a puzzle
  • A moving platform that players must jump between
  • A pendulum trap that reverses direction on a timer
  • A patrol hazard that knocks players back and fires an event when it does

The device exposes two categories of API:

Category What it gives you
Motion control Begin, End, Advance, Reverse, SetTargetDistance, SetTargetSpeed
Reactive events BeganEvent, EndedEvent, FinishedEvent, MovementModeChangedEvent, AgentHitEvent, AIHitEvent, PropHitEvent

API Reference

prop_mover_device

Used to move around a building or prop, and customize responses to various collision event types.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).

prop_mover_device<public> := class<concrete><final>(creative_device_base):

Events (subscribe a handler to react):

Event Signature Description
EnabledEvent EnabledEvent<public>:listenable(tuple()) Signaled when this device is enabled.
DisabledEvent DisabledEvent<public>:listenable(tuple()) Signaled when this device is disabled.
BeganEvent BeganEvent<public>:listenable(tuple()) Signaled when the prop movement begins.
EndedEvent EndedEvent<public>:listenable(tuple()) Signaled when the prop movement ends.
FinishedEvent FinishedEvent<public>:listenable(tuple()) Signaled when the prop reaches its destination.
MovementModeChangedEvent MovementModeChangedEvent<public>:listenable(tuple()) Signaled when the prop changes its direction.
AgentHitEvent AgentHitEvent<public>:listenable(agent) Signaled when the prop hits an agent. Sends the agent hit by the prop.
AIHitEvent AIHitEvent<public>:listenable(tuple()) Signaled when the prop hits a creature, animal, or NPC.
PropHitEvent PropHitEvent<public>:listenable(tuple()) Signaled when the prop hits another prop.

Methods (call these to make the device act):

Method Signature Description
Enable Enable<public>():void Enables this device.
Disable Disable<public>():void Disables this device.
Begin Begin<public>():void Begins the prop moving.
End End<public>():void Ends the prop moving.
Advance Advance<public>():void Moves the prop forward based on this device's default configuration, ignoring the prop's previous movement.
Reverse Reverse<public>():void Reverses the prop's moving direction.
SetTargetDistance SetTargetDistance<public>(InDistance:float):void Sets the total distance (in meters) that the prop will move.
GetTargetDistance GetTargetDistance<public>()<transacts>:float Returns the total distance (in meters) that the prop will move.
SetTargetSpeed SetTargetSpeed<public>(Speed:float):void Sets the speed (in meters per second) at which the prop will move to its destination.
GetTargetSpeed GetTargetSpeed<public>()<transacts>:float Returns the speed (in meters per second) at which the prop mover will move the prop to its destination.

Walkthrough

Scenario: A Timed Crushing Trap

A heavy stone block slides across a corridor. When it hits a player, it reverses. When it reaches the far end, it pauses for two seconds and then advances again. A trigger plate activates the whole system.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

# Drives a sliding stone-block trap.
# Wire: TriggerPlate fires when a player steps on it;
#       PropMover is attached to the stone block prop.
crushing_trap_device := class(creative_device):

    # The prop mover driving the stone block
    @editable
    PropMover : prop_mover_device = prop_mover_device{}

    # A trigger_device the player steps on to activate the trap
    @editable
    TriggerPlate : trigger_device = trigger_device{}

    # How fast the block moves (m/s)
    @editable
    TrapSpeed : float = 4.0

    # How far the block travels (m)
    @editable
    TrapDistance : float = 12.0

    # -------------------------------------------------------
    OnBegin<override>()<suspends> : void =
        # Configure speed and distance before motion starts
        PropMover.SetTargetSpeed(TrapSpeed)
        PropMover.SetTargetDistance(TrapDistance)

        # Subscribe to events
        TriggerPlate.TriggeredEvent.Subscribe(OnPlateTriggered)
        PropMover.AgentHitEvent.Subscribe(OnAgentHit)
        PropMover.FinishedEvent.Subscribe(OnReachedEnd)
        PropMover.MovementModeChangedEvent.Subscribe(OnDirectionChanged)

    # Called when a player steps on the trigger plate
    OnPlateTriggered(Agent : ?agent) : void =
        PropMover.Enable()
        PropMover.Begin()

    # Called when the block crushes a player — reverse immediately
    OnAgentHit(HitAgent : agent) : void =
        PropMover.Reverse()

    # Called when the block reaches the far end — pause then advance again
    OnReachedEnd(Unused : tuple()) : void =
        spawn { PauseAndAdvance() }

    # Called whenever the block changes direction
    OnDirectionChanged(Unused : tuple()) : void =
        # Could play a sound cue, shake camera, etc.
        # Here we just log the event conceptually — real logic goes here
        var CurrentSpeed : float = PropMover.GetTargetSpeed()
        # Optionally ramp speed: PropMover.SetTargetSpeed(CurrentSpeed + 0.5)

    # Waits 2 seconds then sends the block forward again
    PauseAndAdvance()<suspends> : void =
        Sleep(2.0)
        PropMover.Advance()

Line-by-line breakdown:

  • SetTargetSpeed / SetTargetDistance — called in OnBegin before motion starts so the device is fully configured before any player interaction.
  • TriggerPlate.TriggeredEvent.Subscribe(OnPlateTriggered) — the plate's event hands a ?agent; we don't need to unwrap it here because we're just starting the mover.
  • PropMover.AgentHitEvent.Subscribe(OnAgentHit)AgentHitEvent is a listenable(agent) (not optional), so the handler receives a plain agent directly.
  • FinishedEvent — fires when the prop reaches its destination. We spawn a coroutine so Sleep doesn't block the event handler.
  • MovementModeChangedEvent — fires on every direction flip. Useful for SFX, camera shake, or speed escalation.
  • Advance() — resets to the device's default forward direction regardless of previous movement, perfect for restarting a loop.

Common patterns

Pattern 1 — Enable/Disable and runtime speed scaling

A platform that speeds up each time it completes a lap, disabled by a button.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

# Escalating-speed moving platform.
escalating_platform_device := class(creative_device):

    @editable
    Platform : prop_mover_device = prop_mover_device{}

    @editable
    StopButton : button_device = button_device{}

    var LapCount : int = 0
    var BaseSpeed : float = 3.0

    OnBegin<override>()<suspends> : void =
        Platform.SetTargetSpeed(BaseSpeed)
        Platform.Enable()
        Platform.Begin()

        StopButton.InteractedWithEvent.Subscribe(OnStopPressed)
        Platform.FinishedEvent.Subscribe(OnLapComplete)

    OnStopPressed(Agent : agent) : void =
        Platform.End()
        Platform.Disable()

    OnLapComplete(Unused : tuple()) : void =
        set LapCount = LapCount + 1
        # Increase speed by 1 m/s per lap, cap at 15
        var NewSpeed : float = BaseSpeed + (1.0 * LapCount)
        if (NewSpeed > 15.0):
            set NewSpeed = 15.0
        Platform.SetTargetSpeed(NewSpeed)
        Platform.Advance()

Key calls: Enable, Disable, Begin, End, SetTargetSpeed, GetTargetSpeed (pattern shows SetTargetSpeed driving escalation), Advance to restart the loop.


Pattern 2 — Reacting to AI and Prop collisions

A patrol hazard that logs when it hits an NPC or another prop (e.g. a boulder that knocks over barrels).

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

# Patrol hazard that reacts to hitting NPCs and other props.
patrol_hazard_device := class(creative_device):

    @editable
    Hazard : prop_mover_device = prop_mover_device{}

    # How far the hazard patrols (m)
    @editable
    PatrolDistance : float = 20.0

    OnBegin<override>()<suspends> : void =
        Hazard.SetTargetDistance(PatrolDistance)
        Hazard.SetTargetSpeed(5.0)
        Hazard.Enable()
        Hazard.Begin()

        Hazard.AIHitEvent.Subscribe(OnHitAI)
        Hazard.PropHitEvent.Subscribe(OnHitProp)
        Hazard.EndedEvent.Subscribe(OnMovementEnded)

    # Fires when the hazard hits a creature/NPC — reverse and keep going
    OnHitAI(Unused : tuple()) : void =
        Hazard.Reverse()

    # Fires when the hazard hits another prop — slow down briefly
    OnHitProp(Unused : tuple()) : void =
        spawn { SlowAndResume() }

    # Fires when End() is called externally
    OnMovementEnded(Unused : tuple()) : void =
        # Could re-enable after a delay
        spawn { RestartAfterDelay() }

    SlowAndResume()<suspends> : void =
        var OldSpeed : float = Hazard.GetTargetSpeed()
        Hazard.SetTargetSpeed(1.0)
        Sleep(1.5)
        Hazard.SetTargetSpeed(OldSpeed)

    RestartAfterDelay()<suspends> : void =
        Sleep(5.0)
        Hazard.Enable()
        Hazard.Begin()

Key calls: AIHitEvent, PropHitEvent, EndedEvent, Reverse, GetTargetSpeed, SetTargetSpeed.


Pattern 3 — Query distance and speed before starting

A puzzle door that reads its configured values and only starts if they're within safe bounds.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

# Puzzle vault door — validates config before opening.
vault_door_device := class(creative_device):

    @editable
    Door : prop_mover_device = prop_mover_device{}

    @editable
    PuzzleSolvedTrigger : trigger_device = trigger_device{}

    OnBegin<override>()<suspends> : void =
        PuzzleSolvedTrigger.TriggeredEvent.Subscribe(OnPuzzleSolved)
        Door.BeganEvent.Subscribe(OnDoorStarted)
        Door.FinishedEvent.Subscribe(OnDoorFullyOpen)

    OnPuzzleSolved(Agent : ?agent) : void =
        var Dist : float = Door.GetTargetDistance()
        var Speed : float = Door.GetTargetSpeed()
        # Safety clamp: door must travel at least 1m and no faster than 10 m/s
        if (Dist < 1.0):
            Door.SetTargetDistance(1.0)
        if (Speed > 10.0):
            Door.SetTargetSpeed(10.0)
        Door.Enable()
        Door.Begin()

    OnDoorStarted(Unused : tuple()) : void =
        # BeganEvent fires — could trigger a sound or particle effect here
        var _ : float = Door.GetTargetSpeed()  # read current speed if needed

    OnDoorFullyOpen(Unused : tuple()) : void =
        # Door reached destination — disable so it can't be re-triggered
        Door.Disable()

Key calls: GetTargetDistance, GetTargetSpeed, SetTargetDistance, SetTargetSpeed, BeganEvent, FinishedEvent, Enable, Disable, Begin.

Gotchas

1. AgentHitEvent sends agent, not ?agent

AgentHitEvent is typed listenable(agent) — the handler receives a plain agent directly. You do not need to unwrap it with if (A := Agent?):. Contrast this with events like trigger_device.TriggeredEvent which sends ?agent and does require unwrapping.

# CORRECT — plain agent, no unwrap needed
OnAgentHit(HitAgent : agent) : void =
    # use HitAgent directly

# WRONG — this won't compile
# OnAgentHit(HitAgent : ?agent) : void = ...

2. tuple() event handlers must accept the tuple argument

All events typed listenable(tuple())BeganEvent, EndedEvent, FinishedEvent, MovementModeChangedEvent, AIHitEvent, PropHitEvent — require a handler that accepts a tuple() parameter, even though you'll never use it.

# CORRECT
OnFinished(Unused : tuple()) : void =
    PropMover.Advance()

# WRONG — missing the tuple parameter
# OnFinished() : void = ...

3. Never call Sleep directly inside an event handler

Event handlers are not coroutines — calling Sleep inside one will fail to compile. Always spawn a separate <suspends> function.

# CORRECT
OnFinished(Unused : tuple()) : void =
    spawn { PauseAndRestart() }

PauseAndRestart()<suspends> : void =
    Sleep(2.0)
    PropMover.Advance()

# WRONG — Sleep requires <suspends>, event handlers don't have it
# OnFinished(Unused : tuple()) : void =
#     Sleep(2.0)  # compile error

4. Advance vs Begin — they are not the same

  • Begin() starts movement respecting the prop's current state and previous motion.
  • Advance() always moves the prop forward from the device's default configuration, ignoring any previous movement. Use Advance to reliably restart a loop; use Begin to resume from a paused state.

5. Configure speed/distance before calling Begin

SetTargetSpeed and SetTargetDistance take effect immediately, but if you call them after Begin the prop may already be in motion. Set them in OnBegin (the Verse lifecycle method) before any player interaction is possible.

6. The device must be enabled before Begin will work

Calling Begin() on a disabled device has no effect. Always call Enable() first if the device starts disabled in the editor, or if you previously called Disable().

Device Settings & Options

The prop_mover_device User Options panel in the UEFN editor — every setting you can tune.

Prop Mover Device settings and options panel in the UEFN editor — Movement Mode, Rotation Direction, Distance, Rotation Angle, Rotation Duration, Speed, Time From Start
Prop Mover Device — User Options in the UEFN editor: Movement Mode, Rotation Direction, Distance, Rotation Angle, Rotation Duration, Speed, Time From Start
⚙️ Settings on this device (7)

Setting names read from the panel above — may be partial; the screenshots are the source of truth.

Movement Mode
Rotation Direction
Distance
Rotation Angle
Rotation Duration
Speed
Time From Start

Guides & scripts that use prop_mover_device

Step-by-step tutorials that put this object to work.

Build your own lesson with prop_mover_device

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →