Build a Real-Time Countdown Timer in Verse
Tutorial beginner compiles

Build a Real-Time Countdown Timer in Verse

Updated beginner Code verified

What you'll learn

By the end of this guide you will be able to:

  1. Create a canvas and a text_block widget in Verse.
  2. Attach that UI to a player with GetPlayerUI[...] and AddWidget.
  3. Drive a countdown with a loop and Sleep.
  4. Refresh the on-screen text every second by rebuilding the widget content.

How it works

UI in Verse is built from widgets that live inside a player's player_ui. The key APIs from the live digest are:

  • GetPlayerUI[Player] — a <decides> function (note the [] brackets). It fails if the player has no UI, so you must call it inside a failure context such as an if.
  • PlayerUI.AddWidget(Widget) — attaches a widget to the screen. This one is a normal call with ().
  • Sleep(Seconds) — a <suspends> function that pauses the coroutine. Because we await time, our timer must run inside OnBegin<override>()<suspends>.

The important subtlety: a text_block's text is set when the widget is constructed. To make the number change every second we keep a RemainingTime variable, then rebuild the widget's text using a binding so the same on-screen widget re-reads our value. We use a []player list of the widgets/bindings so we can update every player's screen.

The simplest robust pattern (and the one below) is: create ONE text_block per player whose Text reads a message we regenerate, and re-set it each tick. Verse text_block accepts a message for its Text field, and we build that message with string interpolation — never string + concatenation.

Let's build it

This device counts down from TotalTime seconds, showing the remaining whole seconds on the HUD of every player in the playspace and updating once per second.

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

# A real-time countdown timer that renders on every player's screen.
countdown_timer_device := class<concrete>(creative_device):

    # How long the countdown lasts, in seconds. Editable in UEFN.
    @editable
    TotalTime : int = 10

    # Seconds left. We rebuild the text from this each tick.
    var RemainingTime : int = 0

    # Entry point. <suspends> is required because Sleep awaits time.
    OnBegin<override>()<suspends>: void =
        set RemainingTime = TotalTime

        # Build one text widget per player and attach it to their UI.
        # We keep each player's widget so we can refresh its text later.
        var Widgets : []text_block = array{}
        for (Player : GetPlayspace().GetPlayers()):
            # GetPlayerUI is <decides> -> call with [] inside the if.
            if (PUI := GetPlayerUI[Player]):
                TimeText := text_block:
                    DefaultTextColor := NamedColors.White
                    DefaultText := MakeCountdownMessage(RemainingTime)
                # AddWidget is a normal () call, not fallible.
                PUI.AddWidget(TimeText)
                set Widgets += array{TimeText}

        # Drive the countdown: one tick per second until we hit zero.
        loop:
            Sleep(1.0)
            set RemainingTime = RemainingTime - 1
            # Refresh every player's on-screen text.
            for (W : Widgets):
                W.SetText(MakeCountdownMessage(RemainingTime))
            if (RemainingTime <= 0):
                break

    # Build the display text with interpolation (never string '+').
    MakeCountdownMessage(Seconds : int) : message =
        StringToMessage("Time Remaining: {Seconds}")

    # Wrap a string as a message for text_block APIs.
    StringToMessage<localizes>(String : string) : message = "{String}"

Note: text_block sets its content through DefaultText/SetText, which take a message. Because you cannot + a string onto a message, we build the whole line with interpolation inside StringToMessage, a <localizes> helper that turns a plain string into a message.

Try it yourself

  1. Place the device in your level and drop the Verse script onto it.
  2. Set TotalTime in the device's Details panel to any duration you like.
  3. Play the session — every player should see the number tick down once per second.
  4. Extend it: fire a trigger or end the round when RemainingTime hits 0, or change DefaultTextColor to NamedColors.Red for the final few seconds by constructing a second widget.
  5. Late-joiner exercise: subscribe to a player-added event and call GetPlayerUI[NewPlayer] + AddWidget for players who join mid-countdown.

Recap

  • GetPlayerUI[Player] is fallible (<decides>) — always call it with [] inside an if/for condition.
  • AddWidget(...) and Sleep(...) are ordinary () calls; Sleep needs a <suspends> context, which OnBegin provides.
  • A text_block shows a message; build text with interpolation, never string + message.
  • Keep a variable (RemainingTime) as the source of truth and re-set the widget's text each tick to make the display update in real time.
  • Reassign mutables with set (set RemainingTime = RemainingTime - 1) — there is no -= or -- in Verse.

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 a Real-Time Countdown Timer with UI Text Binding 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