Reference Verse compiles

break-out-of-loop: Escape the Infinite with Verse

Every pirate knows when to cut the anchor rope and sail — and in Verse, `break` is that rope. The `loop` expression runs forever until you tell it to stop, and `break` is the one keyword that escapes it cleanly. This article teaches you exactly when and how to use `break`, grounded in real UEFN devices firing on a bright, cel-shaded cove island.

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

Overview

In Verse, loop is an expression that repeats its body indefinitely. Unlike for or while in other languages, loop has no built-in condition — it runs until you explicitly call break inside the body, or until the surrounding async context is cancelled (e.g. by race). Because loop blocks the current coroutine, you almost always pair it with Sleep() so it yields between iterations and doesn't starve other tasks.

When to reach for loop + break:

  • A platform that alternates between visible and invisible on a timer
  • A countdown that ticks every second and stops at zero
  • A VFX cycle that restarts until a player triggers an event
  • Any "keep doing X until Y happens" pattern

Without break, the loop runs for the entire game session. With break, you get a clean, readable exit at exactly the right moment.

API Reference

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

Walkthrough

Scenario: A glowing platform blinks on and off every few seconds. When a player finally lands on a pressure plate nearby, the platform stops blinking and stays visible — the vault door is now permanently open.

This example uses:

  • loop to keep the blink cycle running
  • break to stop the cycle when the plate fires
  • Sleep() to control the on/off timing
  • creative_prop .Hide() / .Show() to toggle the platform mesh
  • vfx_spawner_device .Enable() / .Disable() to sync a glow effect
using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
using { /Fortnite.com }

# Place this device in your UEFN scene, then assign the three
# editable references in the Details panel.
blinking_vault_device := class(creative_device):

    # The platform prop that blinks on and off.
    @editable
    Platform : creative_prop = creative_prop{}

    # A VFX Spawner placed on the platform for the glow effect.
    @editable
    GlowVFX : vfx_spawner_device = vfx_spawner_device{}

    # A Trigger Device — player steps on it to stop the blinking.
    @editable
    Plate : trigger_device = trigger_device{}

    # How long (seconds) the platform stays visible each cycle.
    @editable
    OnDuration : float = 2.0

    # How long (seconds) the platform stays hidden each cycle.
    @editable
    OffDuration : float = 1.5

    # Tracks whether the plate has been triggered.
    var PlateTriggered : logic = false

    # Called when the plate fires — sets the flag that breaks the loop.
    OnPlateTriggered(Agent : ?agent) : void =
        set PlateTriggered = true

    OnBegin<override>()<suspends> : void =
        # Subscribe so any trigger from the plate sets our flag.
        Plate.TriggeredEvent.Subscribe(OnPlateTriggered)

        # Start the blink loop.
        loop:
            # --- VISIBLE phase ---
            Platform.Show()
            GlowVFX.Enable()
            Sleep(OnDuration)

            # Check the exit condition AFTER the sleep so the
            # platform is always fully visible when the player lands.
            if (PlateTriggered?):
                break   # Leave the loop; platform stays visible.

            # --- HIDDEN phase ---
            Platform.Hide()
            GlowVFX.Disable()
            Sleep(OffDuration)

            # Check again after the hidden phase too.
            if (PlateTriggered?):
                # Make sure we restore visibility before exiting.
                Platform.Show()
                GlowVFX.Enable()
                break

Line-by-line explanation:

Lines What's happening
@editable fields Wired in the UEFN Details panel — no hard-coding
var PlateTriggered Shared mutable flag between the event handler and the loop
OnPlateTriggered Event handler (class-scope method) — sets the flag when the plate fires
Plate.TriggeredEvent.Subscribe(...) Registers the handler; TriggeredEvent sends ?agent
loop: Starts the infinite blink cycle
Platform.Show() / Hide() Toggles prop visibility and collision
GlowVFX.Enable() / Disable() Keeps the VFX in sync with the prop
Sleep(OnDuration) Yields for N seconds — other coroutines run during this time
if (PlateTriggered?): break Exits the loop cleanly; code after loop: resumes

Common patterns

Pattern 1 — Countdown timer that stops at zero

A classic round timer: counts down from a starting value, prints nothing (uses Sleep as the tick), and breaks when it hits zero. Pair this with a HUD message device in your real project.

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

countdown_device := class(creative_device):

    # Total seconds to count down.
    @editable
    StartSeconds : int = 30

    OnBegin<override>()<suspends> : void =
        var Remaining : int = StartSeconds

        loop:
            if (Remaining <= 0):
                # Time is up — exit the loop.
                break

            # Wait one second, then decrement.
            Sleep(1.0)
            set Remaining = Remaining - 1

        # Code here runs only after break — trigger end-of-round logic.
        # e.g. EndRoundDevice.Activate()

Key point: The break check comes before the Sleep so the loop exits immediately when the counter reaches zero rather than sleeping one extra second.


Pattern 2 — Random-interval VFX burst cycle

A VFX spawner fires a burst at a random interval between 1 and 4 seconds, forever. No break needed here — the loop runs for the whole game. This demonstrates loop without break as a valid "run forever" pattern, combined with GetRandomFloat.

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

random_burst_device := class(creative_device):

    # A VFX Spawner set to Burst mode in its device settings.
    @editable
    BurstVFX : vfx_spawner_device = vfx_spawner_device{}

    # Minimum seconds between bursts.
    @editable
    MinDelay : float = 1.0

    # Maximum seconds between bursts.
    @editable
    MaxDelay : float = 4.0

    OnBegin<override>()<suspends> : void =
        loop:
            # Fire the burst VFX.
            BurstVFX.Restart()

            # Wait a random amount of time before the next burst.
            var Delay : float = GetRandomFloat(MinDelay, MaxDelay)
            Sleep(Delay)
            # No break — this runs for the entire game session.

Pattern 3 — race as an alternative exit strategy

Sometimes you want the loop to stop when an external async event completes, not a flag. Use race to run the blink loop against a one-shot awaiter. Whichever branch finishes first cancels the other.

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

race_exit_device := class(creative_device):

    @editable
    Platform : creative_prop = creative_prop{}

    @editable
    GlowVFX : vfx_spawner_device = vfx_spawner_device{}

    # When this event fires, the blink loop is cancelled via race.
    @editable
    StopButton : button_device = button_device{}

    # Runs forever, blinking the platform.
    BlinkForever()<suspends> : void =
        loop:
            Platform.Hide()
            GlowVFX.Disable()
            Sleep(1.0)
            Platform.Show()
            GlowVFX.Enable()
            Sleep(2.0)

    # Waits for the button press and then returns, ending the race.
    WaitForStop()<suspends> : void =
        StopButton.InteractedWithEvent.Await()

    OnBegin<override>()<suspends> : void =
        # race cancels BlinkForever the moment WaitForStop returns.
        race:
            BlinkForever()
            WaitForStop()

        # After the race, ensure the platform is visible.
        Platform.Show()
        GlowVFX.Enable()

Gotchas

1. Always Sleep inside a loop or you'll hang the frame

A loop with no Sleep and no break will spin forever in the same tick, freezing your island. Every loop body must either call Sleep() (even Sleep(0.0) to yield once) or be guaranteed to break quickly.

2. break only exits the innermost loop

If you nest two loop expressions, break exits only the inner one. To exit both, use a shared flag and check it in the outer loop too, or restructure with race.

3. TriggeredEvent sends ?agent — always unwrap before use

trigger_device.TriggeredEvent is listenable(?agent). Your handler signature must be (Agent : ?agent) : void. If you need the actual agent, unwrap it: if (A := Agent?) { ... }. Passing the raw ?agent to APIs that expect agent is a compile error.

4. logic flags vs. Await() — know the trade-off

Using a var logic flag (Pattern 1 style) is simple but introduces a one-iteration lag: the loop checks the flag only at the top of each cycle. For instant exits, prefer race with Await() (Pattern 3) so the loop is cancelled the moment the event fires.

5. Sleep takes a float, not an int

Verse does not auto-convert int to float. Sleep(2) is a compile error. Always write Sleep(2.0). If your delay is stored as int, convert explicitly: Sleep(float(MyIntDelay)).

6. vfx_spawner_device lives in /Fortnite.com not /Fortnite.com/Devices

The vfx_spawner_device type is declared inside the Devices module under /Fortnite.com, so you need using { /Fortnite.com } (not just /Fortnite.com/Devices) for it to resolve. Missing this import gives an "Unknown identifier" error.

Guides & scripts that use trigger_device

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

Build your own lesson with trigger_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 →