
The Timing Machine: Concurrency in Verse
The Timing Machine: Concurrency in Verse
In Fortnite islands, lots of things happen at once: a countdown ticks while lights pulse and the HUD updates. Verse handles this with concurrency — first-class language keywords that let you control time flow just like program flow.
What you'll learn
- What concurrency means, and why Verse builds it into the language.
- How
spawnstarts a background task without blocking the current one. - How
raceruns tasks together and stops when the first finishes, cancelling the rest. - How
loopandSleepdrive a per-second countdown. - How to push live updates to a player's screen with the player UI APIs (
GetPlayerUI,AddWidget,text_block).
How it works
Normally Verse runs one line after another — sequential execution. Concurrency lets code overlap in time. Verse's model is cooperative: tasks yield control at suspension points (like Sleep), so there are no data races or deadlocks.
The tools we use:
Sleep(Seconds)— a<suspends>call that pauses the current task, letting others run.spawn— launches an async function in the background; the caller keeps going immediately.race— runs two or more async blocks and stops the moment one finishes, cancelling the rest. Perfect for "count down OR bail after a timeout."loop— repeats a block until youbreak.
Because these are async, they only work inside a <suspends> context — like OnBegin.
To actually SHOW the countdown we grab each player's UI with GetPlayerUI[Player], add a text_block inside a canvas, and rewrite its text each tick with SetText. Note GetPlayerUI[...] is fallible (uses []), so it must be called in a failure context like if. One more Verse rule: UI text APIs take a message, not a plain string — so we define a tiny <localizes> helper (RaceText) that converts our strings into localizable messages.
Let's build it
We'll build a Race Start Device. A player presses a button; the light turns on; a HUD countdown races against a maximum wait time; when it reaches zero the audio plays and the light turns off.
What you need in UEFN: one Button device, one Customizable Light device, and one Audio Player device. Assign each to the matching @editable field, then build.
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/UI }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Localization helper — UI text must be a `message`, not a plain string.
RaceText<localizes>(S : string) : message = "{S}"
# A Race Start device: press the button to run a concurrent, on-screen countdown.
race_start_device := class<concrete>(creative_device):
@editable StartButton : button_device = button_device{} # Player presses to start
@editable StartLight : customizable_light_device = customizable_light_device{} # Turns on during countdown
@editable GoAudio : audio_player_device = audio_player_device{} # Plays on "GO!"
# Entry point — <suspends> so we can await events and run concurrency.
OnBegin<override>()<suspends>: void =
# Device event: no () before .Subscribe. Start a countdown on each press.
StartButton.InteractedWithEvent.Subscribe(OnButtonPressed)
# Handler runs when a player presses the button.
OnButtonPressed(Agent: agent): void =
# spawn launches the async countdown in the background so this handler returns.
spawn { RunCountdown(Agent) }
# The concurrent countdown sequence for the pressing player.
RunCountdown(Agent: agent)<suspends>: void =
StartLight.TurnOn() # Light on while we count
# Build a text widget and add it to the player's HUD.
Label := text_block{DefaultText := RaceText("Ready...")}
if:
Player := player[Agent]
UI := GetPlayerUI[Player] # GetPlayerUI is fallible -> use if
then:
Canvas := canvas:
Slots := array:
canvas_slot:
Anchors := anchors{Minimum := vector2{X := 0.5, Y := 0.2}, Maximum := vector2{X := 0.5, Y := 0.2}}
Widget := Label
UI.AddWidget(Canvas)
# race: whichever branch finishes first wins; the loser is cancelled.
# - CountdownLoop ticks 3..2..1 into the label, then returns
# - Sleep(10.0) is a safety timeout that cancels a stuck countdown
race:
CountdownLoop(Label)
Sleep(10.0)
Label.SetText(RaceText("GO!"))
# Fire the audio and clean up the light + widget.
GoAudio.Play(Agent)
StartLight.TurnOff()
Sleep(1.0)
UI.RemoveWidget(Canvas)
# Counts down from 3, rewriting the on-screen label every second.
CountdownLoop(Label : text_block)<suspends>: void =
var Remaining : int = 3
loop:
if (Remaining <= 0):
break # Countdown done — leave the loop
Label.SetText(RaceText("Countdown: {Remaining}"))
Print("Countdown: {Remaining}")
Sleep(1.0) # yield one second
set Remaining = Remaining - 1 # use set to reassign a var```
## Try it yourself
* Change the timeout in `Sleep(10.0)` to `2.0` and watch the safety branch win the race, cancelling the countdown early.
* Show the countdown to **everyone** by looping `for (Player : GetPlayspace().GetPlayers())` and adding a widget per player.
* Add a second async block to the `race` that waits on `StartButton.InteractedWithEvent.Await(...)` so a second press aborts the countdown.
* Swap the light for a color pulse loop running inside the same `race`.
## Recap
* **Concurrency** in Verse controls time flow with language keywords — no threads, mutexes, or data races.
* **`spawn`** starts background work; **`race`** runs blocks together and keeps the first to finish; **`loop`** + **`Sleep`** drive per-tick timing.
* These require a `<suspends>` context like `OnBegin`.
* Real UI comes from `GetPlayerUI[Agent]` (fallible — call it in an `if`), `AddWidget`, a `canvas` with `text_block`, and `SetText` to update each tick — always feeding it a `message` built by a `<localizes>` helper.
* Reassign a `var` with `set`, and remember device events subscribe without `()` while character events need them.
Verse source files
- 01-device.verse · device
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 Verse concurrency: spawn, sync, race, and loop for game timing 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.
References
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.