Booth Buttons: Bridging Device Interactions into Verse
In this lesson you'll learn to
- βStudent can subscribe to button InteractedWithEvent, read the interacting agent, and route it into their own functions.
Student can subscribe to button InteractedWithEvent, read the interacting agent, and route it into their own functions.
π Reference & full walkthrough: Booth Buttons: Bridging Device Interactions into Verse
π Builds on: south-shores: one-responsibility-per-function (clean handler functions)
π§© Your capstone piece: The interact button at each of the 5 zone-portal booths
What you'll learn
- How to subscribe to
InteractedWithEventon abutton_device. - How to safely cast an
agentto aplayerand get theirplayer_uiwithGetPlayerUI[...]. - How to add and later remove a
text_blockwidget from a player's screen.
How it works
- Subscribe: In
OnBegin, we callButton.InteractedWithEvent.Subscribe(HandleButtonInteraction). Device events use.Subscribedirectly (no parentheses on the event), unlike character events. - Handler receives an agent: The handler is passed the
agentwho interacted. An agent can be a player OR AI, so we can't use it directly for UI. - Cast + get UI in one failure context:
if (InPlayer := player[Agent], PlayerUI := GetPlayerUI[InPlayer]):casts the agent to a player and fetches that player's UI. Both are fallible ([]) calls, so they live inside anifcondition. - Track state per widget: We store the current widget in a per-player
weak_mapoption. If a widget already exists we remove it, then add a fresh one showing the updated count.
Why the failure context?
player[Agent]andGetPlayerUI[InPlayer]are<decides>calls β the[]brackets are only legal inside anif,for, or other failure context. If the agent is an AI, the cast simply fails and we skip the UI code.
Let's build it
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Displays a per-player click counter widget when a Button device is pressed.
button_ui_device := class<concrete>(creative_device):
@editable
Button : button_device = button_device{}
# How many times each player has clicked. weak_map keyed by agent.
var ClickCounts : [agent]int = map{}
# The current widget shown to each player, so we can remove it before re-adding.
var ShownWidgets : [agent]?text_block = map{}
OnBegin<override>()<suspends> : void =
# Device events subscribe WITHOUT parentheses on the event itself.
Button.InteractedWithEvent.Subscribe(HandleButtonInteraction)
# Runs whenever a player interacts with the Button device.
HandleButtonInteraction(Agent : agent) : void =
# Cast the agent to a player AND fetch their UI in one failure context.
# Both [] calls are fallible; AI agents will simply fail the cast here.
if (InPlayer := player[Agent], PlayerUI := GetPlayerUI[InPlayer]):
# Compute the new click count for this player.
var Count : int = 0
if (Existing := ClickCounts[Agent]):
set Count = Existing
set Count = Count + 1
if (set ClickCounts[Agent] = Count) {}
# Remove any widget we previously showed this player.
if (Old := ShownWidgets[Agent]?):
PlayerUI.RemoveWidget(Old)
# Build a fresh text widget with the updated count and show it.
NewWidget : text_block = text_block{DefaultText := ClickMessage}
NewWidget.SetText(StringToMessage("Clicked {Count} times!"))
PlayerUI.AddWidget(NewWidget)
if (set ShownWidgets[Agent] = option{NewWidget}) {}
Print("Button pressed! Player count is now {Count}")
# Default text shown before SetText overrides it.
ClickMessage<localizes> : message = "Clicked!"
# Wrap a string into a message so text_block can display it.
StringToMessage<localizes>(S : string) : message = "{S}"
Try it yourself
- Add a second
button_deviceand give each its own counter map. - After showing the widget,
Sleep(3.0)then callPlayerUI.RemoveWidget(NewWidget)to auto-hide it (you'll need to restructure into aspawn{}). - Wrap the
text_blockin astack_boxoroverlayfor custom positioning.
Recap
- Device events like
InteractedWithEventuse.Subscribe(Handler)directly. - Handlers get an
agent; cast withplayer[Agent]inside a failure context before touching UI. GetPlayerUI[InPlayer]returns aplayer_ui; useAddWidget/RemoveWidgetto manage that player's on-screen widgets.- Track shown widgets in an option map so you can remove the old one before adding a new one.
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 lessonSources
/guides/sug-subscribing-to-button-device-interaction-events-in-verseBiloxi Studios original lesson
Add this lesson to your free study plan.
π§ The Keeperβs log
Quest complete? Chart your next heading from the π§ Center Village (Free) expedition.
β΅ Take me there