Reference Verse compiles

String Concatenation in Verse: Dynamic HUD Messages on the Pirate Cove

Your pirate cove island needs more than static signs — when a player steps on a dock trigger, you want to flash a personalized welcome message like "Ahoy, Buccaneer! You found the hidden cove!" That means stitching strings together at runtime. In Verse, string concatenation is done with the `{variable}` interpolation syntax inside a string expression, and the `Concatenate` function for arrays of strings. This article shows you exactly how to build those dynamic strings and pipe them to a `hud_me

Updated Examples verified on the live UEFN compiler
Watch the Knottrigger_device in ~90 seconds.

Overview

String concatenation is the act of gluing pieces of text together into one bigger string. In Verse you rarely reach for a Concat() device — the language itself gives you two clean tools:

  • The + operator joins two string values: "Hello, " + Name.
  • String interpolation drops any expression straight into a literal with curly braces: "Score: {Points}".

The game problem this solves is dynamic feedback. A trigger on the dock doesn't know a player's name at build time, and a shell counter changes every second. Concatenation lets you assemble a fresh sentence at runtime — "Welcome, surfer #3!" — and then show it.

The one catch: UEFN's on-screen UI (like HUD Message) and any device parameter typed message do not take a raw string. You concatenate your string, then wrap it in a <localizes> function to turn it into a message. That wrapping step is the bridge between "text you built" and "text a player sees." We'll use it in every example, styled around a sunny 2D cove.

API Reference

(API surface could not be resolved for this device.)

Walkthrough

Picture a wooden dock jutting into a turquoise cove. Each time a player steps on the trigger plate at the end of the dock, we bump a counter and flash a personalized welcome banner on screen: "Aloha, surfer #3 — welcome to Sunset Cove!"

The player's display name comes from GetFortCharacter() / agent APIs, but for a name-free version we'll build the banner purely from a running count plus static shore text — pure concatenation and interpolation. The banner uses player.GetPlayerUI() and ShowMessage, both from using { /UnrealEngine.com/Temporary/UI }.

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

cove_greeter := class(creative_device):

    # The dock plate players walk onto.
    @editable DockPlate : trigger_device = trigger_device{}

    # A running tally of how many surfers have arrived.
    var VisitorCount : int = 0

    # Wrap a finished string into a localized message for the UI.
    Banner<localizes>(S : string) : message = "{S}"

    OnBegin<override>()<suspends>:void =
        # When someone steps on the dock, greet them.
        DockPlate.TriggeredEvent.Subscribe(OnDockStepped)

    OnDockStepped(Agent : ?agent) : void =
        # A listenable(?agent) event hands us an optional agent — unwrap it.
        if (A := Agent?):
            # Bump the counter.
            set VisitorCount += 1

            # Build the sentence with interpolation + the + operator.
            Middle : string = "Aloha, surfer #{VisitorCount}"
            FullText : string = Middle + " — welcome to Sunset Cove!"

            # Wrap the finished string as a message and show it on that player's UI.
            if (Player := player[A]):
                UI := Player.GetPlayerUI()
                UI.ShowMessage(Banner(FullText))

Line by line:

  • @editable DockPlate : trigger_device — a placed trigger you drag into the field in the Details panel. You can't call methods on a bare device; it must be an editable field.
  • var VisitorCount : int = 0 — mutable state we grow every arrival.
  • Banner<localizes>(S : string) : message = "{S}" — the tiny helper that turns any string into a message. There is no StringToMessage built-in; this pattern is the idiomatic replacement.
  • DockPlate.TriggeredEvent.Subscribe(OnDockStepped) — subscribing in OnBegin wires the plate to our handler method.
  • OnDockStepped(Agent : ?agent) — the TriggeredEvent is a listenable(?agent), so the handler receives an optional agent. if (A := Agent?) unwraps it.
  • set VisitorCount += 1 — increment before building text so the count reads correctly.
  • Middle : string = "Aloha, surfer #{VisitorCount}"interpolation: the int VisitorCount is converted to text inside the braces automatically (this is a display conversion, not an int→float cast).
  • FullText := Middle + " — welcome..." — the + operator joins two strings into one.
  • player[A] casts the agent to a player, then GetPlayerUI() + ShowMessage(Banner(FullText)) renders the assembled, localized sentence.

Drop this device on the island, assign the trigger, and every step on the dock greets the arriving surfer with a fresh, correctly-numbered banner.

Common patterns

Pattern 1 — Interpolate a score into a HUD line

A button on the clifftop awards a shell; the message rebuilds the tally each press using interpolation of two ints.

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

shell_counter := class(creative_device):

    @editable ShellButton : button_device = button_device{}
    var Collected : int = 0
    Goal : int = 5

    ToMessage<localizes>(S : string) : message = "{S}"

    OnBegin<override>()<suspends>:void =
        ShellButton.InteractedWithEvent.Subscribe(OnPressed)

    OnPressed(Agent : agent) : void =
        set Collected += 1
        # Two interpolated ints inside one literal.
        Line : string = "Shells: {Collected}/{Goal}"
        if (Player := player[Agent]):
            Player.GetPlayerUI().ShowMessage(ToMessage(Line))

Pattern 2 — Join several fragments with +

Build a longer sentence from multiple pieces, mixing static shore-flavor text with a dynamic count.

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

tide_reporter := class(creative_device):

    @editable TidePlate : trigger_device = trigger_device{}
    var WaveNumber : int = 0

    Say<localizes>(S : string) : message = "{S}"

    OnBegin<override>()<suspends>:void =
        TidePlate.TriggeredEvent.Subscribe(OnWave)

    OnWave(Agent : ?agent) : void =
        if (A := Agent?):
            set WaveNumber += 1
            # Assemble from parts with the + operator.
            Prefix : string = "The tide rolls in... "
            Count : string = "wave {WaveNumber}"
            Suffix : string = " crashes on the cove."
            Report : string = Prefix + Count + Suffix
            if (Player := player[A]):
                Player.GetPlayerUI().ShowMessage(Say(Report))

Pattern 3 — Concatenate a name onto a greeting

Pull a value into a variable, glue it on, and show a per-player line.

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

sunrise_welcome := class(creative_device):

    @editable StartPlate : trigger_device = trigger_device{}
    IslandName : string = "Sunset Cove"

    Greet<localizes>(S : string) : message = "{S}"

    OnBegin<override>()<suspends>:void =
        StartPlate.TriggeredEvent.Subscribe(OnArrive)

    OnArrive(Agent : ?agent) : void =
        if (A := Agent?):
            # Concatenate greeting + island name with interpolation folded in.
            Message : string = "Good morning! You've reached " + IslandName + "."
            if (Player := player[A]):
                Player.GetPlayerUI().ShowMessage(Greet(Message))

Gotchas

  • message is not string. Any UI or device parameter typed message rejects a raw string. Always route through a <localizes> helper like Banner<localizes>(S:string):message = "{S}". There is no StringToMessage function — don't search for one.
  • Interpolation is a display conversion, not a numeric cast. "Score: {MyInt}" works fine, but Verse still won't auto-convert int to float in arithmetic. Interpolation only formats a value into text.
  • Unwrap the optional agent. TriggeredEvent is listenable(?agent), so the handler gets (Agent : ?agent). Use if (A := Agent?): before you touch it. button_device.InteractedWithEvent hands you a plain agent, so no unwrap is needed there — mixing them up causes type errors.
  • player[Agent] can fail. Casting an agent to a player is a <decides> operation; wrap it in if (Player := player[A]): so the code only runs for real players, not non-player agents.
  • Bare devices don't compile. You cannot call TidePlate.TriggeredEvent... unless TidePlate is an @editable field on your creative_device and assigned in the editor. A local placeholder will never fire.
  • + only joins two strings at a time, but it chains: A + B + C is fine. If a piece is an int, interpolate it into a string first ("{N}") rather than trying to + a number onto text.

Guides & scripts that use trigger_device

Step-by-step tutorials that put this object to work.

Build your own lesson with trigger_device

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →