Say It With Braces: String Interpolation

In this lesson you'll learn to

  • βœ“Student can build dynamic strings like "Shells: {Count}/{Total}" and push them to the HUD every time state changes.

Student can build dynamic strings like "Shells: {Count}/{Total}" and push them to the HUD every time state changes.

πŸ“– Reference & full walkthrough: Say It With Braces: String Interpolation

🧩 Your capstone piece: The live 'Shells: {n}/{Total}' counter text on the hunt HUD


Overview

String interpolation in Verse lets you embed any value that has a ToString() function into a string literal using {curly braces}. The result is a plain string β€” but Verse's HUD devices speak message, a localization-safe type. The bridge is a <localizes> helper function you write once and reuse everywhere.

When to reach for this combo:

  • Show a personalised "Welcome, {Name}!" splash when a player spawns on your lagoon island.
  • Display a live countdown: "Cannon fires in {Seconds}s!" on the HUD.
  • Announce the winner: "First to the treasure: {WinnerName}!" to every player.

The hud_message_device is the workhorse. It can target one player or all players, accept a custom message at call-time (no pre-baking in the editor), control display duration, and be hidden or cleared programmatically β€” all from Verse.

API Reference

hud_message_device

Used to show custom HUD messages to one or more agents.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).

hud_message_device<public> := class<concrete><final>(creative_device_base):

Events (subscribe a handler to react):

Event Signature Description
ShowMessageEvent ShowMessageEvent<public>:listenable(agent) Called when a Message has been Shown on-screen. Returns an Agent if it was Shown on a specified Agent's screen.
HideMessageEvent HideMessageEvent<public>:listenable(agent) Called when a Message has been Hidden on-screen. Returns an Agent if it was Hidden from a specified Agent's screen.
ClearAllMessagesEvent ClearAllMessagesEvent<public>:listenable(agent) Called when all queued Messages from all players that are affected by this HUD Message Device have been cleared.

Methods (call these to make the device act):

Method Signature Description
Show Show<public>(Agent:agent):void Shows the currently set HUD Message on Agents screen. Will replace any previously active message. Use this when the device is setup to target specific agents.
Show Show<public>():void Shows the currently set Message HUD message on screen. Will replace any previously active message.
Hide Hide<public>():void Hides the HUD message.
Hide Hide<public>(Agent:agent):void Hides the currently set HUD Message on Agents screen. Use this when the device is setup to target specific agents.
Show Show<public>(Agent:agent, Message:message, ?DisplayTime:float Displays a Custom message to a specific Agent that you define.Setting DisplayTime to 0.0 will display the HUD message persistently.If not defined, or less than 0.0 the message will show for the time set on the device.
Show Show<public>(Message:message, ?DisplayTime:float Displays a Custom message that you define for all PlayersSetting DisplayTime to 0.0 will display the HUD message persistently.If not defined, or less than 0.0 the message will show for the time set on the device.
SetDisplayTime SetDisplayTime<public>(Time:float):void Sets the time (in seconds) the HUD message will be displayed. 0.0 will display the HUD message persistently.
GetDisplayTime GetDisplayTime<public>()<transacts>:float Returns the time (in seconds) for which the HUD message will be displayed. 0.0 means the message is displayed persistently.
SetText SetText<public>(Text:message):void Sets the Message to be displayed when the HUD message is activated. Text is clamped to 150 characters.
ClearAllMessages ClearAllMessages<public>():void Clears all queued Messages from all players that are affected by this HUD Message Device.

player

Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from agent.

player<native><public> := class<unique><persistent><module_scoped_var_weak_map_key><epic_internal>(agent):

Walkthrough

Scenario: A 2D cel-shaded pirate cove. When a player steps onto the dock's pressure plate, the HUD shows them a personalised welcome message with a wave countdown, then clears it automatically after the ship departs.

This example uses:

  • Show(Agent, Message, ?DisplayTime) β€” targeted, interpolated message
  • SetDisplayTime β€” change the linger time at runtime
  • GetDisplayTime β€” read it back for the countdown string
  • ClearAllMessages β€” wipe the board when the ship leaves
  • ShowMessageEvent β€” react when the message appears
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Fortnite.com/Playspaces }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

# Attach this device to your island. Wire DockPlate and WelcomeHUD in the editor.
dock_welcome_device := class(creative_device):

    # The pressure plate on the dock the player steps on
    @editable
    DockPlate : trigger_device = trigger_device{}

    # The HUD message device placed in the scene
    @editable
    WelcomeHUD : hud_message_device = hud_message_device{}

    # --- Localization helpers ---
    # Verse requires `message` type for HUD text; use a <localizes> function as the bridge.
    WelcomeText<localizes>(Name : string, Secs : string) : message =
        "Ahoy, {Name}! Ship departs in {Secs}s β€” grab yer loot!"

    DepartureText<localizes>() : message =
        "The ship has left the cove. All hands accounted for!"

    # --- Entry point ---
    OnBegin<override>()<suspends> : void =
        # Show the message for 8 seconds by default; we'll read it back for the countdown.
        WelcomeHUD.SetDisplayTime(8.0)

        # Subscribe to the plate so we react when any player steps on it.
        DockPlate.TriggeredEvent.Subscribe(OnPlayerSteppedOnDock)

        # Subscribe to ShowMessageEvent to log confirmation (covers the event surface).
        WelcomeHUD.ShowMessageEvent.Subscribe(OnMessageShown)

        # Keep the coroutine alive forever so subscriptions stay active.
        Sleep(Inf)

    # --- Triggered when a player steps on the dock plate ---
    OnPlayerSteppedOnDock(Agent : ?agent) : void =
        if (A := Agent?):
            if (Player := player[A]):
                # Get the player's display name via fort_character if available,
                # otherwise fall back to a pirate nickname.
                var DisplayName : string = "Stranger"
                if (FortChar := A.GetFortCharacter[]):
                    # fort_character doesn't expose a name directly; use a fun fallback.
                    set DisplayName = "Buccaneer"

                # Read back the current display time so we can interpolate it into the string.
                CurrentSecs := WelcomeHUD.GetDisplayTime()
                # ToString converts float -> string for interpolation.
                SecsString : string = ToString(CurrentSecs)

                # Build the interpolated message and show it to THIS player only.
                WelcomeHUD.Show(A, WelcomeText(DisplayName, SecsString))

                # After the display time elapses, clear all messages (ship departs).
                spawn { ClearAfterDelay(CurrentSecs) }

    # --- Clears the board after the ship departs ---
    ClearAfterDelay(Delay : float)<suspends> : void =
        Sleep(Delay)
        # Show a global departure announcement to ALL players, then clear.
        WelcomeHUD.Show(DepartureText(), ?DisplayTime := 3.0)
        Sleep(3.0)
        WelcomeHUD.ClearAllMessages()

    # --- Fires when ShowMessageEvent signals ---
    OnMessageShown(Agent : agent) : void =
        # React to the event β€” e.g. play a sound device, start a timer UI, etc.
        # Here we simply note it fired; in a real island you'd chain another device.
        var _unused : int = 0  # no-op placeholder; replace with your device call```

### Line-by-line highlights

| Lines | What's happening |
|---|---|
| `WelcomeText<localizes>(...)` | The `<localizes>` attribute turns a function returning `message` into a valid `message` factory. The body uses `{Name}` and `{Secs}` β€” classic string interpolation. |
| `WelcomeHUD.SetDisplayTime(8.0)` | Sets how long the HUD lingers before auto-hiding. |
| `WelcomeHUD.GetDisplayTime()` | Reads that value back as a `float` so we can interpolate it into the countdown string. |
| `ToString(CurrentSecs)` | Converts `float` β†’ `string` so it can be embedded with `{SecsString}`. |
| `WelcomeHUD.Show(A, WelcomeText(...))` | Targeted show β€” only this player sees the message. |
| `WelcomeHUD.Show(DepartureText(), ?DisplayTime := 3.0)` | Global show with an inline display-time override. |
| `WelcomeHUD.ClearAllMessages()` | Wipes every queued message for every player. |
| `WelcomeHUD.ShowMessageEvent.Subscribe(OnMessageShown)` | Reacts when the message actually appears on screen. |

## Common patterns

### Pattern 1 β€” Persistent score banner (SetText + Show)

Use `SetText` to pre-load an interpolated message into the device, then call the no-argument `Show()` to broadcast it to everyone. Good for a score update that fires from a separate scoring device.

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

score_banner_device := class(creative_device):

    @editable
    ScoreHUD : hud_message_device = hud_message_device{}

    # Localizes helper: embeds the team name and score into a message.
    ScoreText<localizes>(Team : string, Points : string) : message =
        "☠ {Team} leads with {Points} doubloons!"

    OnBegin<override>()<suspends> : void =
        # Simulate a score update at game start.
        TeamName : string = "Crimson Sails"
        Points : int = 42
        # int has no implicit ToString; use string interpolation directly β€” int does have ToString.
        PointsStr : string = "{Points}"  # interpolation calls int's ToString automatically
        # Pre-load the text into the device.
        ScoreHUD.SetText(ScoreText(TeamName, PointsStr))
        # Show persistently to all players (DisplayTime 0.0 = forever).
        ScoreHUD.SetDisplayTime(0.0)
        ScoreHUD.Show()
        Sleep(Inf)

Pattern 2 β€” Hide a message when a player leaves the zone (Hide per agent)

When a player exits the dock area, hide the HUD only for them, leaving other players' messages intact.

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

dock_exit_device := class(creative_device):

    @editable
    ExitPlate : trigger_device = trigger_device{}

    @editable
    DockHUD : hud_message_device = hud_message_device{}

    # Subscribes to HideMessageEvent to chain another effect.
    OnMessageHidden(Agent : agent) : void =
        # Agent's message was hidden β€” e.g. re-enable their movement here.
        var _ : int = 0  # replace with your follow-up device call

    OnBegin<override>()<suspends> : void =
        ExitPlate.TriggeredEvent.Subscribe(OnPlayerExited)
        DockHUD.HideMessageEvent.Subscribe(OnMessageHidden)
        Sleep(Inf)

    OnPlayerExited(Agent : ?agent) : void =
        if (A := Agent?):
            # Hide the HUD only for this specific agent.
            DockHUD.Hide(A)

Pattern 3 β€” Dynamic countdown using GetDisplayTime + ToString

Poll GetDisplayTime in a loop, interpolate the remaining seconds into a string, and push updates every second β€” a live countdown on the lagoon cliff.

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

countdown_hud_device := class(creative_device):

    @editable
    CountdownHUD : hud_message_device = hud_message_device{}

    CountdownText<localizes>(Secs : string) : message =
        "βš“ Cannon fires in {Secs}s!"

    OnBegin<override>()<suspends> : void =
        TotalSeconds : float = 10.0
        CountdownHUD.SetDisplayTime(0.0)  # persistent; we control it manually

        var Remaining : float = TotalSeconds
        loop:
            if (Remaining <= 0.0):
                break
            SecsStr : string = ToString(Remaining)
            # Show the interpolated countdown to all players.
            CountdownHUD.Show(CountdownText(SecsStr))
            Sleep(1.0)
            set Remaining = Remaining - 1.0

        # Countdown done β€” clear everything.
        CountdownHUD.ClearAllMessages()

Gotchas

1. string β‰  message β€” you MUST use a <localizes> function

The HUD device's Show and SetText methods accept message, not string. You cannot pass a raw string literal or a string variable directly. The only correct bridge is a function annotated <localizes>:

# βœ… Correct
MyMsg<localizes>(S : string) : message = "Ahoy, {S}!"
HUD.Show(Agent, MyMsg("Pirate"))

# ❌ Won't compile β€” string is not message
HUD.Show(Agent, "Ahoy, Pirate!")

There is no StringToMessage function in Verse. The <localizes> pattern is the only way.

2. int and float are not strings β€” interpolate or call ToString

Verse does not auto-convert numeric types to string. Use either ToString(MyFloat) or embed the value directly in a string interpolation expression "{MyInt}" (which calls the type's implicit ToString):

Score : int = 99
# βœ…
ScoreStr : string = "{Score}"
# βœ…
ScoreStr2 : string = ToString(Score)  # only if ToString(int) is in scope; prefer interpolation
# ❌ type mismatch
# ScoreStr3 : string = Score

3. listenable(?agent) events must be unwrapped

trigger_device.TriggeredEvent hands your handler a ?agent (option type). Always unwrap before using:

OnTriggered(Agent : ?agent) : void =
    if (A := Agent?):   # unwrap the option
        HUD.Show(A, MyMsg("Pirate"))  # now A is a concrete agent

Skipping the unwrap causes a compile error β€” ?agent is not agent.

4. SetDisplayTime(0.0) means persistent, not instant-hide

Passing 0.0 to SetDisplayTime (or the ?DisplayTime named argument) makes the message stay on screen forever until you call Hide or ClearAllMessages. Use a positive float for a timed message.

5. Show(Message, ?DisplayTime) overrides the device's stored time only for that call

The named-argument variant Show(MyMsg, ?DisplayTime := 5.0) does not permanently change the device's display time β€” it only affects that single call. SetDisplayTime is the persistent setter; GetDisplayTime reflects that persistent value, not a per-call override.

πŸ”’

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/string-interpolation
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 🦩 South Shores (Free) expedition.

β›΅ Take me there