Marooned Town: fire-and-forget with spawn

In this lesson you'll learn to

  • βœ“Student can launch independent async tasks with spawn{} and knows when spawn is right vs. awaiting inline.

Student can launch independent async tasks with spawn{} and knows when spawn is right vs. awaiting inline.

πŸ“– Reference & full walkthrough: Marooned Town: fire-and-forget with spawn

🧩 Your capstone piece: One spawned per-racer monitor task (position/checkpoint watcher) per player at race start


What you'll learn

You'll learn how to launch a Verse function asynchronously with the spawn expression so background work never freezes gameplay. You'll combine Sleep for timed delays, GetRandomFloat for variable timing, and the player's HUD message device (hud_message_device) to deliver a delayed, non-blocking UI update to each player. The same pattern powers countdowns, live stats, and staggered notifications.

How it works

Verse runs your device logic cooperatively on a single thread. If you put a long Sleep loop directly inside an event handler, that handler holds the line until it finishes. The spawn expression breaks free of that: it starts a <suspends> function as an independent task that runs alongside everything else. Your TriggeredEvent handler returns immediately while the spawned task waits, then updates the UI later.

Three rules matter here:

  • The spawned function MUST be marked <suspends> because it calls Sleep.
  • spawn{ Foo() } (or spawn Foo()) is called with PARENS β€” Foo is an ordinary <suspends> function, not a <decides> one.
  • GetRandomFloat is <transacts> and returns a plain float, so call it with () and store the value β€” no brackets.

To make the result visible we drive a hud_message_device. Calling Show(Agent) displays its configured text on that player's HUD, which is our concrete "UI update."

Let's build it

Place a Trigger Device and a HUD Message Device (with some text configured) in your level, then assign both to the Verse device below. Stepping on the trigger spawns a background task that waits a random 1–3 seconds, then shows the HUD message to the player who triggered it.

using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
using { /Verse.org/Random }
using { /Verse.org/Verse }
using { /UnrealEngine.com/Temporary/Diagnostics }

# A device that spawns a background task to update the Player UI (HUD) after a delay.
spawn_ui_device := class<concrete>(creative_device):

    # The trigger the player steps on to kick off the async task.
    @editable TriggerDevice : trigger_device = trigger_device{}

    # The HUD message shown to the player once the background task finishes.
    @editable SuccessMessage : hud_message_device = hud_message_device{}

    # Async task: wait a random amount of time, then update the player's HUD.
    # Marked <suspends> because it calls Sleep.
    UpdatePlayerUIAsync(TriggeringAgent : agent)<suspends> : void =
        # GetRandomFloat is <transacts> and returns a float β€” call with (), store it.
        Delay : float = GetRandomFloat(1.0, 3.0)
        Print("Background task started, waiting {Delay} seconds...")

        # Yield this task for the delay; the rest of the game keeps running.
        Sleep(Delay)

        # Update the UI: show the configured HUD message to the triggering player.
        SuccessMessage.Show(TriggeringAgent)
        Print("UI updated for the player after the delay.")

    # Entry point.
    OnBegin<override>()<suspends> : void =
        # Subscribe to the trigger. The handler returns immediately because the
        # slow work is launched with spawn instead of run inline.
        TriggerDevice.TriggeredEvent.Subscribe(OnTriggered)

    # Event handler: not <suspends>, so it must NOT call Sleep directly.
    # spawn launches the async function as an independent task.
    # The TriggeredEvent passes an ?agent, so accept that and bind it.
    OnTriggered(MaybeAgent : ?agent) : void =
        Print("Trigger fired β€” spawning background UI task.")
        if (Agent := MaybeAgent?):
            spawn{ UpdatePlayerUIAsync(Agent) }```

## Try it yourself

1. Place a **Trigger Device** and a **HUD Message Device** in your level.
2. On the HUD Message Device, set its **Message** text (e.g. "Success!").
3. Place a **Verse Device** running `spawn_ui_device`.
4. In its details panel, assign the Trigger to `TriggerDevice` and the HUD Message Device to `SuccessMessage`.
5. Play, step on the trigger, and keep moving. The game never freezes β€” the HUD message appears 1–3 seconds later thanks to the spawned task.

## Recap

You used `spawn` to run a `<suspends>` function as an independent background task, keeping your trigger handler instant and non-blocking. `Sleep` provided the timed delay, `GetRandomFloat` (called with parens, returning a `float`) varied the timing, and `hud_message_device.Show(Agent)` delivered the actual UI update. Reach for `spawn` when you need fire-and-forget async work; reach for `race`, `sync`, or `branch` when you need structured coordination.
πŸ”’

Keep going β€” free

You've read the intro. The rest of this lesson is free for members. Sign in to continue and track your progress.

Sign in free to continue this lesson
Pass the quiz above to chart this quest in your Journal.

Sources

/guides/sug-launching-asynchronous-logic-with-spawn-in-verse
Source

Biloxi Studios original lesson

Guided course

Add this lesson to your free study plan.

🧭 The Keeper’s log

Quest complete? Chart your next heading from the πŸ¦‘ West Coves expedition.

β›΅ Take me there