move-prop-moveto: Animating Props Through Verse
Tutorialintermediatecompiles

move-prop-moveto: Animating Props Through Verse

Updated intermediateDevicesCode verified

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 }
verse
Result := MyProp.MoveTo(TargetPos, TargetRot, 2.0)
# Result is move_to_result — check its value if needed

Get the complete code — free

You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.

Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.

Check your understanding

Test yourself with an interactive quiz and track your progress + earn XP — free for members.

Turn this into a guided course

Add Moving creative_prop instances smoothly through the world using MoveTo and TeleportTo in Verse to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.

Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.

Comments

    Sign in to vote, comment, or suggest an edit.Sign in