Master Verse Rush for Concurrent Game Logic
Tutorialintermediatecompiles

Master Verse Rush for Concurrent Game Logic

Updated intermediateCode verified

What you'll learn

In Verse, time flow is a first-class language feature. Normally code runs top-to-bottom, one expression after another. But games are inherently concurrent: enemies spawn, HUDs animate, and timers tick all at the same moment. The rush expression groups two or more async expressions (functions marked <suspends>, Sleep, event awaits) so they start together.

The key behavior that sets rush apart from race: when the fastest subexpression completes, the expression that follows rush is evaluated — but the slower subexpressions are not canceled. They keep running to completion. That makes rush ideal for kicking off independent background work while reacting immediately to the first result.

How it works

Think of rush like a director shouting "Action!" at several actors simultaneously. All subexpressions begin at once. As soon as one finishes, your code moves on, but the others continue in the background.

A few rules that keep rush correct:

  • rush may only appear in a <suspends> context (like OnBegin), because its subexpressions are async.
  • Every subexpression must itself be async — calling Sleep, awaiting an event, or invoking a <suspends> helper.
  • To actually accomplish something visible, our subtasks call real player-UI APIs. We reach the HUD with Player.GetPlayerUI[] (a <decides> call, so it goes in an if) and push widgets with PlayerUI.AddWidget(Widget).

We build a text_block widget, show it immediately in one subtask, then in a second subtask wait two seconds and swap the displayed text. Because both subtasks live inside rush, the immediate update and the delayed update are scheduled concurrently and neither blocks the other.

Let's build it

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

# A device that shows a HUD message, then concurrently updates it after a delay using `rush`.
rush_ui_device := class<concrete>(creative_device):

    # Async helper: show initial text on the player's HUD immediately.
    # It is <suspends> so it can be a rush subexpression; Sleep(0.0) yields once.
    ShowOnline(TextWidget:text_block)<suspends>:void =
        Print("Task 1: pushing 'System Online' to HUD")
        TextWidget.SetText(StringToMessage("System Online"))
        Sleep(0.0)  # yield to other concurrent tasks this frame
        Print("Task 1: HUD update sent")

    # Async helper: wait, then swap the HUD text. Runs concurrently with ShowOnline.
    ShowComplete(TextWidget:text_block)<suspends>:void =
        Print("Task 2: waiting 2 seconds...")
        Sleep(2.0)
        TextWidget.SetText(StringToMessage("Task Complete"))
        Print("Task 2: delayed HUD update sent")

    # Convert a plain string into a message for the text_block.
    StringToMessage<localizes>(Value:string):message = "{Value}"

    OnBegin<override>()<suspends>:void =
        # Reach the first player; GetPlayers() returns an array, array{0} is fallible.
        if (Player := GetPlayspace().GetPlayers()[0]):
            # GetPlayerUI is <decides> — call it inside the if and bind the result.
            if (PlayerUI := GetPlayerUI[Player]):
                # Build a real text widget and add it to the HUD before rushing.
                Label := text_block{DefaultText := StringToMessage("Booting...")}
                PlayerUI.AddWidget(Label)

                # rush: both subtasks start together. When the fastest (ShowOnline)
                # completes, execution continues past rush; ShowComplete keeps running.
                rush:
                    ShowOnline(Label)
                    ShowComplete(Label)

                Print("rush returned (fastest task done); slower task still finishing.")

Try it yourself

  • Add a third subtask to the rush block (for example, one that Sleep(1.0) then prints) and observe that the line after rush fires as soon as the fastest one finishes, while the others continue.
  • Swap rush for race and watch the difference: race cancels the slower tasks, so the 2-second update never appears.
  • Replace Sleep(0.0) in ShowOnline with Sleep(3.0) so it becomes the slowest. Notice the post-rush line now fires when ShowComplete finishes instead.
  • Capture a rush result by assigning it: Result := rush: ... and feed the winner into your next expression.

Recap

  • rush runs two or more async expressions concurrently and continues as soon as the fastest completes — without canceling the slower ones (unlike race).
  • It must live in a <suspends> context, and every subexpression must be async.
  • We performed the technique for real: GetPlayerUI[Player] (a <decides> call inside if) plus AddWidget and text_block.SetText to drive a live HUD from concurrent tasks.
  • Use rush for independent background work where one immediate result shouldn't wait on slower side effects.

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 Implementing Concurrent Logic with Rush Expressions 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