Reference Verse

text_block: Dynamic UI Text in Verse

The text_block widget is your go-to tool for displaying dynamic text on a player's HUD, such as scores, health, or announcements. This guide covers how to bind, format, and update text_block elements using Verse to bring your UI to life.

Updated

Overview

The text_block widget is a fundamental UI element in UEFN used to render text on a canvas or user widget. Unlike placed level devices, text_block elements live inside your UI designs and are bound to your Verse scripts. You reach for text_block when you need to update a player's score, display a health value, or show a localized announcement dynamically during gameplay. By manipulating its properties through Verse, you can change the text content, color, size, and opacity on the fly.

API Reference

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

Walkthrough

Let's build a Score Tracker that updates a text_block whenever a player steps on a trigger. Because UI widgets are bound in the UEFN UI Designer rather than placed in the level viewport, we declare them as optional (?) fields and unwrap them safely in our code.

score_tracker_device := class(creative_device):
    @editable
    ScoreText : ?text_block = option{}

    @editable
    ScoreTrigger : trigger_device = trigger_device{}

    var CurrentScore : int = 0

    # Localized message helper for SetText
    ScoreMessage<localizes>(Score:int):message = "Score: {Score}"

    OnBegin<override>()<suspends>:void =
        ScoreTrigger.TriggeredEvent.Subscribe(OnScoreTriggered)
        UpdateScoreUI()

    OnScoreTriggered(Agent : ?agent):void =
        if (A := Agent?):
            CurrentScore += 1
            UpdateScoreUI()

    UpdateScoreUI():void =
        # Unwrap the optional UI widget binding
        if (Text := ScoreText?):
            # SetText requires a localized message, not a raw string
            Text.SetText(ScoreMessage(CurrentScore))
            
            # SetTextSize requires a float, not an int
            Text.SetTextSize(48.0)
            
            # SetTextColor uses the color struct (R, G, B, A from 0.0 to 1.0)
            Text.SetTextColor(color{R:=1.0, G:=1.0, B:=0.0, A:=1.0})

Common patterns

Health Bar Color Change

Change the text color and opacity based on the player's current health. This pattern demonstrates conditional styling and using SetTextOpacity.

health_ui_device := class(creative_device):
    @editable
    HealthText : ?text_block = option{}

    HealthMessage<localizes>(H:int):message = "HP: {H}"

    OnBegin<override>()<suspends>:void =
        SetHealth(25)

    SetHealth(CurrentHP:int):void =
        if (Text := HealthText?):
            Text.SetText(HealthMessage(CurrentHP))
            if (CurrentHP <= 25):
                # Low health: Red and fully opaque
                Text.SetTextColor(color{R:=1.0, G:=0.0, B:=0.0, A:=1.0})
                Text.SetTextOpacity(1.0)
            else:
                # Normal health: Green
                Text.SetTextColor(color{R:=0.0, G:=1.0, B:=0.0, A:=1.0})

Fading Announcement Text

Display a large, semi-transparent announcement. This pattern shows how to combine SetTextSize and SetTextOpacity for stylistic UI effects.

fading_text_device := class(creative_device):
    @editable
    FadingText : ?text_block = option{}

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

    OnBegin<override>()<suspends>:void =
        ShowFadingText("Mission Complete")

    ShowFadingText(Msg:string):void =
        if (Text := FadingText?):
            Text.SetText(FadingMessage(Msg))
            Text.SetTextSize(72.0)
            Text.SetTextOpacity(0.5)

Gotchas

  • SetText requires a message, not a string: You cannot pass a raw string like "Score: 10" to SetText. You must define a <localizes> function that returns a message type and pass your variables as interpolants (e.g., "{Score}").
  • No auto int-to-float conversion: Methods like SetTextSize and SetTextOpacity strictly require float values. Passing 48 (an int) will cause a compile error; you must write 48.0.
  • UI Widgets vs. Placed Devices: A text_block is a UI widget, not a level device. You do not drag it into the 3D viewport. Instead, you design it in a Verse-powered UI Widget blueprint, and then bind it to your @editable field in the UEFN Details panel.
  • Always unwrap optional bindings: Because UI bindings can be left unassigned in the editor, it is best practice to declare them as optional (?text_block) and unwrap them with if (Text := MyText?): before calling methods to prevent runtime crashes.

Guides & scripts that use text_block_widget

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

Build your own lesson with text_block_widget

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 →