Reference Verse compiles

move-prop-moveto: Animating Props Through Verse

Want a vault door that slides open when a player steps on a pressure plate, or a platform that glides between waypoints during a race? The `creative_prop` API's `MoveTo` method lets you animate any placed prop to a new position and rotation over time — all from Verse code. This article covers the full workflow: referencing props as editable fields, calling `MoveTo` with position/rotation/duration, teleporting props instantly, and chaining moves for multi-waypoint sequences.

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

Overview

In UEFN, a creative_prop is any static mesh object you place in your island — a door, a platform, a crate, a barrier. By default these objects sit still. The creative_prop Verse API gives you programmatic control over them:

  • MoveTo(Position, Rotation, OverTime) — smoothly interpolates the prop to a target position and rotation over a given number of seconds. It is a <suspends> function, meaning it blocks the current coroutine until the move finishes (or is interrupted). It returns a move_to_result you can inspect.
  • TeleportTo(Position, Rotation) — instantly snaps the prop to a location with no animation. Useful for resetting a prop between rounds.
  • Show() / Hide() — toggle visibility and collision, handy for revealing props at the right moment.
  • SetLinearVelocity() / ApplyLinearImpulse() — physics-based motion when physics is enabled on the prop.

Reach for MoveTo whenever you need timed, smooth prop animation driven by game events — opening doors, rising platforms, sliding barriers, moving objective markers.

API Reference

(API surface could not be resolved for this device.)

Walkthrough

Scenario: A Vault Door That Slides Open

A player steps on a pressure plate. A heavy vault door slides sideways 400 cm over 1.5 seconds, stays open for 5 seconds, then slides back and locks. A second plate can reset the door instantly.

Setup in UEFN:

  1. Place a static mesh prop (your door) in the scene.
  2. Place two button_device objects — one to open, one to reset.
  3. Place this Verse device in the scene and wire up the three @editable fields in the Details panel.
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Fortnite.com/Devices }

# vault_door_device — slides a prop open on button press, resets on a second button.
vault_door_device := class(creative_device):

    # The prop acting as the vault door.
    @editable
    DoorProp : creative_prop = creative_prop{}

    # Button a player interacts with to open the door.
    @editable
    OpenButton : button_device = button_device{}

    # Button that instantly resets the door to its closed position.
    @editable
    ResetButton : button_device = button_device{}

    # How far the door slides open (cm along the world X axis).
    OpenOffsetCM : float = 400.0

    # Duration of the open/close slide animation in seconds.
    SlideDuration : float = 1.5

    # How long the door stays open before auto-closing.
    OpenHoldSeconds : float = 5.0

    # Store the closed transform so we can return to it.
    var ClosedTransform : transform = transform{}

    OnBegin<override>()<suspends> : void =
        # Capture the door's starting transform as the "closed" state.
        set ClosedTransform = DoorProp.GetTransform()

        # Subscribe to both buttons.
        OpenButton.InteractedWithEvent.Subscribe(OnOpenPressed)
        ResetButton.InteractedWithEvent.Subscribe(OnResetPressed)

    # Called when the open button is interacted with.
    OnOpenPressed(Agent : agent) : void =
        spawn { RunDoorSequence() }

    # Called when the reset button is interacted with.
    OnResetPressed(Agent : agent) : void =
        # TeleportTo snaps the door back instantly — no animation.
        ClosedPos := ClosedTransform.Translation
        ClosedRot := ClosedTransform.Rotation
        if (DoorProp.TeleportTo[ClosedPos, ClosedRot]):
            # Teleport succeeded — door is reset.

    # Coroutine: slide open, wait, slide closed.
    RunDoorSequence()<suspends> : void =
        # Build the open position: offset 400 cm along world X from closed pos.
        ClosedPos := ClosedTransform.Translation
        OpenPos := vector3{
            X := ClosedPos.X + OpenOffsetCM
            Y := ClosedPos.Y
            Z := ClosedPos.Z
        }
        ClosedRot := ClosedTransform.Rotation

        # Slide the door open over SlideDuration seconds.
        DoorProp.MoveTo(OpenPos, ClosedRot, SlideDuration)

        # Hold open.
        Sleep(OpenHoldSeconds)

        # Slide the door closed.
        DoorProp.MoveTo(ClosedPos, ClosedRot, SlideDuration)```

**Line-by-line explanation:**

| Lines | What's happening |
|---|---|
| `@editable` fields | Expose `DoorProp`, `OpenButton`, `ResetButton` to the UEFN Details panel so you can wire up real scene objects without hardcoding. |
| `set ClosedTransform = DoorProp.GetTransform()` | Snapshots the door's starting transform at game-begin so we always know where "closed" is. |
| `Subscribe(OnOpenPressed)` | Hooks the button's `InteractedWithEvent`  fires whenever any player interacts. |
| `spawn { RunDoorSequence() }` | Launches the slide coroutine without blocking `OnOpenPressed` (which is not `<suspends>`). |
| `if (DoorProp.TeleportTo[ClosedPos, ClosedRot])` | `TeleportTo` is `<decides>`  it can fail, so we call it inside `if` with `[]` failure-context syntax. |
| `DoorProp.MoveTo(OpenPos, ClosedRot, SlideDuration)` | Smoothly moves the door. Because `RunDoorSequence` is `<suspends>`, execution pauses here until the move completes. |
| `Sleep(OpenHoldSeconds)` | Waits 5 seconds before auto-closing. |

---

## Common patterns

### Pattern 1 — Multi-waypoint platform loop

A floating platform visits three waypoints in a loop, useful for a parkour challenge.

```verse
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Fortnite.com/Devices }

looping_platform_device := class(creative_device):

    @editable
    Platform : creative_prop = creative_prop{}

    # Travel time between each waypoint in seconds.
    LegDuration : float = 3.0

    OnBegin<override>()<suspends> : void =
        StartPos := Platform.GetTransform().Translation
        StartRot := Platform.GetTransform().Rotation

        # Three waypoints relative to start (cm offsets).
        WaypointA := vector3{ X := StartPos.X + 500.0, Y := StartPos.Y, Z := StartPos.Z }
        WaypointB := vector3{ X := StartPos.X + 500.0, Y := StartPos.Y + 500.0, Z := StartPos.Z + 300.0 }

        # Loop forever.
        loop:
            Platform.MoveTo(WaypointA, StartRot, LegDuration)
            Platform.MoveTo(WaypointB, StartRot, LegDuration)
            Platform.MoveTo(StartPos,  StartRot, LegDuration)

Key point: Each MoveTo suspends until complete, so the loop naturally sequences the three legs one after another with no extra synchronisation needed.


Pattern 2 — Show a hidden prop then fly it into place

A treasure chest is hidden at game start. When a trigger fires, it appears and rises dramatically into view.

using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Fortnite.com/Devices }

treasure_reveal_device := class(creative_device):

    @editable
    Chest : creative_prop = creative_prop{}

    @editable
    RevealTrigger : trigger_device = trigger_device{}

    OnBegin<override>()<suspends> : void =
        # Hide the chest at game start.
        Chest.Hide()
        RevealTrigger.TriggeredEvent.Subscribe(OnReveal)

    OnReveal(Agent : ?agent) : void =
        spawn { RevealSequence() }

    RevealSequence()<suspends> : void =
        BuriedPos := Chest.GetTransform().Translation
        RaisedPos  := vector3{
            X := BuriedPos.X
            Y := BuriedPos.Y
            Z := BuriedPos.Z + 250.0
        }
        IdleRot := Chest.GetTransform().Rotation

        # Make the chest visible before animating.
        Chest.Show()

        # Rise up over 2 seconds.
        Chest.MoveTo(RaisedPos, IdleRot, 2.0)

Key point: Hide() and Show() control both visibility AND collision. Always call Show() before MoveTo if the prop starts hidden — a hidden prop can still be moved, but players won't see the animation.


Pattern 3 — Instant reset with TeleportTo after round end

After a round ends, all moving obstacles snap back to their start positions instantly so the next round can begin cleanly.

using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Fortnite.com/Devices }

obstacle_reset_device := class(creative_device):

    @editable
    ObstacleA : creative_prop = creative_prop{}

    @editable
    ObstacleB : creative_prop = creative_prop{}

    @editable
    RoundManager : round_settings_device = round_settings_device{}

    var HomeA : transform = transform{}
    var HomeB : transform = transform{}

    OnBegin<override>()<suspends> : void =
        set HomeA = ObstacleA.GetTransform()
        set HomeB = ObstacleB.GetTransform()
        RoundManager.RoundEndedEvent.Subscribe(OnRoundEnd)

    OnRoundEnd(Index : int) : void =
        # TeleportTo is <decides> — wrap in if to handle potential failure.
        if (ObstacleA.TeleportTo[HomeA.Translation, HomeA.Rotation]):
        if (ObstacleB.TeleportTo[HomeB.Translation, HomeB.Rotation]):

Key point: TeleportTo is <transacts><decides> — it can fail (e.g. if the prop has been disposed). Always call it inside an if expression using [] syntax.


Gotchas

1. MoveTo is <suspends> — you MUST call it from a coroutine

MoveTo blocks until the move finishes. You cannot call it directly from an event handler (which is not <suspends>). Always spawn { MyCoroutine() } from the handler and put MoveTo inside the coroutine.

# WRONG — won't compile: handler is not <suspends>
OnTriggered(Agent : ?agent) : void =
    MyProp.MoveTo(TargetPos, TargetRot, 2.0)  # ERROR

# CORRECT
OnTriggered(Agent : ?agent) : void =
    spawn { DoMove() }

DoMove()<suspends> : void =
    MyProp.MoveTo(TargetPos, TargetRot, 2.0)  # OK

2. TeleportTo is <decides> — always wrap in if

TeleportTo can fail (disposed prop, invalid position). Call it with [] inside an if:

if (MyProp.TeleportTo[NewPos, NewRot]):
    # success

Calling it without if will cause a compile error.

3. All @editable prop fields MUST be assigned in the Details panel

If you leave an @editable creative_prop field unassigned (pointing to the default empty creative_prop{}), MoveTo will throw a Verse runtime error at the MoveToInternal call. Always assign every prop reference before pressing Play.

4. vector3 fields require explicit float literals

Verse does not auto-convert int to float. Write 400.0, not 400:

# WRONG
OpenPos := vector3{ X := ClosedPos.X + 400, Y := ClosedPos.Y, Z := ClosedPos.Z }
# CORRECT
OpenPos := vector3{ X := ClosedPos.X + 400.0, Y := ClosedPos.Y, Z := ClosedPos.Z }

5. Spawning multiple MoveTo coroutines on the same prop

If you spawn a new RunDoorSequence while one is already running, both will fight over the prop. Guard against this with a var IsMoving : logic = false flag, or use race to cancel the previous coroutine before starting a new one.

6. move_to_result — check it if you care about interruption

MoveTo returns a move_to_result. If another MoveTo or TeleportTo interrupts the current move, the result reflects that. For most game uses you can ignore the return value, but for cutscenes or precise sequencing, capture and inspect it:

Result := MyProp.MoveTo(TargetPos, TargetRot, 2.0)
# Result is move_to_result — check its value if needed

Build your own lesson with move_prop_moveto

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 →