Reference Verse compiles

trigger_device: Relay Events Across Your Island

On a sunny cel-shaded cove, a wooden pressure plate on the dock should fire a chain of events — but only a few times before the tide comes in. The trigger_device is the humble relay that makes this happen, and Verse's continue/skip iteration lets you fan a single trigger out to a whole crowd of beachgoers cleanly.

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

Overview

In many languages you write continue; to jump straight to the next iteration of a loop. Verse has no continue statement. Instead, Verse loops (for, loop) skip work using the language's failure model: if the guard at the top of the loop body fails, the rest of that iteration is abandoned and the loop moves on to the next element.

Think of a bright clifftop finish line. When the round ends you sweep through every player on the island. Some are on the winning team, some aren't. You want to teleport ONLY the winners to the victory cove, award them points, and skip everyone else — without stopping the loop. That 'skip this one, keep going' behavior is exactly what a failable guard inside a for gives you.

The two everyday shapes are:

  • for (X : Collection, Guard[X]) { ... } — the filter is baked into the for header. Elements that fail Guard[X] are silently skipped. This is the closest thing to continue.
  • for (X : Collection) { if (Guard[X]) { DoWork(X) } } — the guard is an if inside the body. When if fails, the body after it is skipped and the loop continues to the next element.

Because there's no device called continue-skip-iteration, the code here uses real placed devices — teleporter_device, score_manager_device, and timer_device — as the work you selectively run per iteration.

API Reference

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

Walkthrough

Scenario: the round timer completes on a sunny clifftop. We loop over every player. For each player we check a condition; players who pass get teleported to the victory cove and awarded points, players who fail are skipped — but the loop keeps running for the rest.

using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
using { /Fortnite.com/Characters }

# Sweeps all players when the round timer finishes.
# Winners are teleported + scored; everyone else is SKIPPED.
victory_sweep := class(creative_device):

    # Placed devices we drive per iteration.
    @editable
    RoundTimer : timer_device = timer_device{}

    @editable
    VictoryTeleporter : teleporter_device = teleporter_device{}

    @editable
    WinnerScore : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends>:void =
        # When the timer succeeds, run our sweep.
        RoundTimer.SuccessEvent.Subscribe(OnRoundOver)
        RoundTimer.Start()

    # SuccessEvent hands us a ?agent (may be empty).
    OnRoundOver(MaybeAgent : ?agent):void =
        # Grab every player currently in the match.
        AllPlayers := GetPlayspace().GetPlayers()

        # Loop over all of them. The guard in the body decides
        # whether this iteration does work or is skipped.
        for (P : AllPlayers):
            # 'continue/skip': if this fails, the rest of the
            # body is abandoned and we move to the next player.
            if (IsWinner[P]):
                # This player qualified -> do the real work.
                VictoryTeleporter.Teleport(P)
                WinnerScore.Activate(P)

    # Failable predicate: succeeds only for players we want to reward.
    # Replace this with your real win condition.
    IsWinner(P : player)<transacts><decides>:void =
        # Example gate: the player must be a valid, fortnite character.
        FC := P.GetFortCharacter[]
        FC.IsActive[]```

Line by line:

- The three `@editable` fields are the placed devices. You drop a Timer, Teleporter and Score Manager on the island and assign them in the Details panel.
- `OnBegin` subscribes `OnRoundOver` to the timer's `SuccessEvent` and starts the timer with `RoundTimer.Start()`.
- `SuccessEvent` is a `listenable(?agent)`, so the handler signature is `(MaybeAgent : ?agent)`. We don't need that agent here, so we ignore it.
- `GetPlayspace().GetPlayers()` returns the array we iterate.
- The `for (P : AllPlayers)` walks every player. Inside, `if (IsWinner[P])` is the **skip gate**: when `IsWinner[P]` fails, everything after the `if` is skipped for THAT player and the loop simply proceeds to the next one  that's the Verse version of `continue`.
- Winners get `Teleport(P)` and `Activate(P)` (the agent overload that awards points to that specific player).
- `IsWinner` uses `<decides>` (it can fail). The `[]` call syntax runs it in a failure context. Swap the body for your real win check.

## Common patterns

### 1. Skip in the `for` header (the tightest 'continue')

Instead of an inner `if`, bake the filter into the `for` itself. Any player failing `HasCharacter[P]` is skipped before the body ever runs. Here we increment a score bump for each qualifying player.

```verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }

header_filter_scorer := class(creative_device):

    @editable
    Score : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends>:void =
        AllPlayers := GetPlayspace().GetPlayers()
        # Filter clause in the header: non-matching players are skipped.
        for (P : AllPlayers, HasCharacter[P]):
            # Only reached for players that passed the filter.
            Score.Increment(P)
            Score.Activate(P)

    HasCharacter(P : player)<transacts><decides>:void =
        FC := P.GetFortCharacter[]
        FC.IsActive[]

2. Skip missing array elements while looping devices

When looping an array of optional teleporters, use the inner if to skip empty slots and keep going. Only valid destinations get activated.

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

teleport_all_valid := class(creative_device):

    # A row of teleporters along the dock; some slots may be empty.
    @editable
    Teleporters : []teleporter_device = array{}

    @editable
    StartRift : teleporter_device = teleporter_device{}

    OnBegin<override>()<suspends>:void =
        StartRift.EnterEvent.Subscribe(OnEnter)

    OnEnter(Entrant : agent):void =
        for (T : Teleporters):
            # Enable each teleporter; if any op fails we skip it.
            T.Enable()
            T.ActivateLinkToTarget()

3. Countdown loop that skips ticks until a condition holds

A loop with Sleep is a common async pattern. Each pass we check a guard; when it fails we skip the body work and let the loop Sleep again — effectively 'continue to next tick'.

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

pulse_timer := class(creative_device):

    @editable
    Beacon : timer_device = timer_device{}

    var Beats : int = 0

    OnBegin<override>()<suspends>:void =
        loop:
            Sleep(1.0)
            set Beats += 1
            # Skip the reset work unless we've hit 5 beats.
            if (Beats >= 5):
                Beacon.Reset()
                set Beats = 0
            # (If the if fails, we skip straight to the next loop pass.)

Gotchas

  • There is no continue keyword. Reaching for continue/break from another language will not compile. Use a failable if guard (skip) or break is likewise absent — restructure with guards instead.
  • for header filters short-circuit before the body. for (P : Ps, Guard[P]) never runs the body for failing elements — this is usually clearer than an inner if when you're just filtering.
  • ?agent events must be unwrapped. timer_device.SuccessEvent is listenable(?agent); the handler receives ?agent. If you need the actual agent, unwrap with if (A := MaybeAgent?): before using it.
  • <decides> predicates use [], not (). Call IsWinner[P] inside a failure context (an if, or a for filter clause). Calling it with () will not compile.
  • Agent vs. no-agent device overloads. Score.Activate(P) awards to a specific player; Score.Activate() uses the device's default. Pick the overload that matches whether your device's Activating Team is set to a specific team.
  • Int/float don't auto-convert. In the countdown pattern, Beats is int and Sleep takes a float literal (1.0). Don't mix them.

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 →