Overview
The scoreboard-update pattern in UEFN is built from two cooperating devices:
| Device | Role |
|---|---|
score_manager_device |
Awards, increments, decrements, and resets points for individual players or the whole island. |
player_reference_device |
Tracks a specific agent, exposes their stats to other devices, and fires events whenever those stats change. |
Reach for this pair whenever you need:
- A live leaderboard that reacts to in-game events (crate pickups, eliminations, lap completions).
- Bonus-point logic that increments a score before awarding it.
- Cinematic reactions (a fanfare sequence) triggered the moment a player's score changes.
Neither device requires a single line of Verse to function at the most basic level, but Verse unlocks the full power: conditional bonuses, chained events, and cross-device orchestration.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario — Crate Rush on the Sunny Dock
Players spawn on a cel-shaded dock above a glittering cove. A damage_volume_device marks the "score zone" at the end of the dock. When a player enters the zone:
- Their score is incremented (bonus multiplier tick).
- Points are awarded via
Activate. - A
player_reference_devicedetects the stat change and fires acinematic_sequence_devicefanfare.
Place these devices in your UEFN level and wire them to the Verse device below.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
# dock_score_manager — awards points when a player enters the score zone
# and plays a fanfare whenever any tracked stat changes.
dock_score_manager := class(creative_device):
# The damage volume placed at the end of the dock (score zone).
@editable
ScoreZone : damage_volume_device = damage_volume_device{}
# Grants points to the agent who enters the score zone.
@editable
ScoreManager : score_manager_device = score_manager_device{}
# Tracks the agent currently highlighted on the scoreboard.
@editable
PlayerRef : player_reference_device = player_reference_device{}
# Plays a short cel-shaded fanfare cinematic when a score updates.
@editable
FanfareSequence : cinematic_sequence_device = cinematic_sequence_device{}
# Entry point — subscribe to all relevant events.
OnBegin<override>()<suspends> : void =
# When a player walks into the dock score zone, award them points.
ScoreZone.AgentEntersEvent.Subscribe(OnPlayerEntersZone)
# When the player reference device detects a stat change, play the fanfare.
PlayerRef.TrackedStatChangedEvent.Subscribe(OnStatChanged)
# Called every time an agent steps into the score zone.
OnPlayerEntersZone(Agent : agent) : void =
# Increment the pending score by 1 (bonus multiplier tick).
ScoreManager.Increment(Agent)
# Award the accumulated points to this agent.
ScoreManager.Activate(Agent)
# Register this agent with the player reference device so
# the scoreboard highlights them and tracks their new stat.
PlayerRef.Register(Agent)
# Called by PlayerRef whenever the tracked agent's stat changes.
OnStatChanged(Agent : agent) : void =
# Play the fanfare for everyone — no instigating agent needed.
FanfareSequence.Play()
Line-by-line explanation
| Lines | What's happening |
|---|---|
@editable fields |
Expose each placed device to the UEFN Details panel so you can wire them without hard-coding. |
ScoreZone.AgentEntersEvent.Subscribe(OnPlayerEntersZone) |
Listens for any agent walking into the dock end-zone volume. |
ScoreManager.Increment(Agent) |
Bumps the pending award up by 1 before it is granted — great for a streak multiplier. |
ScoreManager.Activate(Agent) |
Actually grants the accumulated points to that specific agent. |
PlayerRef.Register(Agent) |
Tells the Player Reference device to start tracking this agent's stats, which will fire TrackedStatChangedEvent. |
FanfareSequence.Play() |
Triggers the cinematic for all players the moment the scoreboard updates. |
Common patterns
Pattern 1 — Reset a player's score when they fall off the dock
A second damage_volume_device covers the water below. Falling in resets the score manager so the player starts fresh.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
dock_reset_on_fall := class(creative_device):
# Volume covering the water below the dock.
@editable
WaterVolume : damage_volume_device = damage_volume_device{}
# The same score manager used for awarding points.
@editable
ScoreManager : score_manager_device = score_manager_device{}
# Player reference device — clear it when the player falls.
@editable
PlayerRef : player_reference_device = player_reference_device{}
OnBegin<override>()<suspends> : void =
WaterVolume.AgentEntersEvent.Subscribe(OnPlayerFallsInWater)
OnPlayerFallsInWater(Agent : agent) : void =
# Reset the score manager back to its original state for this agent.
ScoreManager.Reset(Agent)
# Clear the player reference device so the scoreboard stops
# highlighting a player who is no longer in contention.
PlayerRef.Clear()
Pattern 2 — Decrement score for risky behaviour (jumping off the clifftop)
A trigger at the clifftop edge decrements the pending award before the next activation, penalising reckless players.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
dock_clifftop_penalty := class(creative_device):
# Volume at the clifftop edge — entering it costs a point.
@editable
CliffEdgeVolume : damage_volume_device = damage_volume_device{}
# Shared score manager.
@editable
ScoreManager : score_manager_device = score_manager_device{}
OnBegin<override>()<suspends> : void =
CliffEdgeVolume.AgentEntersEvent.Subscribe(OnPlayerNearEdge)
OnPlayerNearEdge(Agent : agent) : void =
# Decrement the pending award by 1 as a penalty.
ScoreManager.Decrement(Agent)
Pattern 3 — React to MaxTriggersEvent to end the round
When the score manager has been triggered the maximum number of times (set in device settings), fire a cinematic end-of-round sequence and teleport everyone to the shore celebration spot.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
dock_round_ender := class(creative_device):
# Score manager configured with a finite Times Can Trigger limit.
@editable
ScoreManager : score_manager_device = score_manager_device{}
# End-of-round cinematic (camera pan across the cove).
@editable
EndSequence : cinematic_sequence_device = cinematic_sequence_device{}
# Teleporter that sends everyone to the shore celebration area.
@editable
CelebrationTeleporter : teleporter_device = teleporter_device{}
# Player reference device — used to retrieve the winning agent.
@editable
PlayerRef : player_reference_device = player_reference_device{}
OnBegin<override>()<suspends> : void =
# MaxTriggersEvent fires when the score manager hits its trigger cap.
ScoreManager.MaxTriggersEvent.Subscribe(OnRoundComplete)
# Agent is the last player who triggered the score manager.
OnRoundComplete(Agent : agent) : void =
# Play the end-of-round cinematic for all players.
EndSequence.Play()
# Teleport the winning agent to the celebration shore.
CelebrationTeleporter.Teleport(Agent)
# Disable the score manager so no more points can be awarded.
ScoreManager.Disable()
Gotchas
1. Decrement is NOT in the resolved API surface shown above — verify before shipping
The grounding lists Increment but the symmetric Decrement may exist on score_manager_device in the live digest. Always check the UEFN API browser before relying on it; if it is absent, use a negative-value workaround via device settings instead.
2. TrackedStatChangedEvent only fires for the currently registered agent
player_reference_device tracks one agent at a time. If you call Register for a new agent before the previous agent's stat event fires, you may miss the old agent's update. Register agents only after their score action is complete.
3. MaxTriggersEvent sends agent, not ?agent
Unlike timer_device.SuccessEvent (which sends ?agent), score_manager_device.MaxTriggersEvent sends a non-optional agent — no unwrapping needed. Don't add a redundant if (A := Agent?) guard here.
4. Enable/Disable have overloads — pick the right one
score_manager_device.Enable() (no args) affects all players; Enable(Agent:agent) affects only that player. Calling the wrong overload is a silent logic bug — the compiler won't complain.
5. player_reference_device.Activate() ends the round/game
The Activate method on player_reference_device is documented as "Ends the round/game" — it is NOT a generic activation helper. Do not confuse it with score_manager_device.Activate(Agent) which awards points.
6. Localized message params
If you pass text to any device that accepts a message parameter, you cannot use a raw string. Declare a localizes helper:
MyLabel<localizes>(S : string) : message = "{S}"
There is no StringToMessage function in Verse.
7. int ↔ float is never automatic
damage_volume_device.SetDamage takes int; if you compute damage from a float expression, cast explicitly with Int[MyFloat] (which can fail, so handle the failure case).