Overview
An array in Verse is an ordered, zero-indexed collection of values of the same type. Unlike many languages, Verse arrays are value types — every mutation produces a new array, so you must store the result back into a var field. You reach for arrays whenever you need to:
- Track a dynamic list of players (e.g. everyone who stepped on a pressure plate)
- Maintain a queue of objectives or spawn points
- Store references to multiple placed devices so you can iterate over them
- Build a leaderboard, inventory, or wave roster that changes at runtime
The three operations you will use most are:
- Append —
set MyArray += array{NewItem}grows the array by one element. - RemoveAllElements — removes every occurrence of a value, returning a new array.
- Remove — removes a slice by index range, returning a new array (failable).
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: Capture-Point Roster
A capture point tracks which players are standing inside it. When a player enters the zone a trigger_device fires; when they leave a second trigger fires. The Verse device maintains a var []player roster, adds arriving players, removes departing ones, and announces the current count via a hud_message_device.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Displays the current roster count on-screen.
RosterCountText<localizes>(N : int) : message = "Players on point: {N}"
capture_point_roster_device := class(creative_device):
# Drop a trigger_device inside the capture zone — set it to fire on player enter.
@editable
EnterTrigger : trigger_device = trigger_device{}
# A second trigger_device just outside the zone — fires when a player leaves.
@editable
ExitTrigger : trigger_device = trigger_device{}
# A HUD Message device to show the current count.
@editable
HudMsg : hud_message_device = hud_message_device{}
# The live roster — starts empty.
var Roster : []player = array{}
OnBegin<override>()<suspends> : void =
EnterTrigger.TriggeredEvent.Subscribe(OnPlayerEntered)
ExitTrigger.TriggeredEvent.Subscribe(OnPlayerLeft)
# Called when a player steps INTO the capture zone.
OnPlayerEntered(Agent : ?agent) : void =
if (A := Agent?):
if (P := player[A]):
# Append the player to the roster.
set Roster += array{P}
HudMsg.SetText(RosterCountText(Roster.Length))
# Called when a player steps OUT of the capture zone.
OnPlayerLeft(Agent : ?agent) : void =
if (A := Agent?):
if (P := player[A]):
# Build a new array that excludes this player.
var NewRoster : []player = array{}
for (Existing : Roster):
if (Existing <> P):
set NewRoster += array{Existing}
set Roster = NewRoster
HudMsg.SetText(RosterCountText(Roster.Length))
Line-by-line explanation
| Lines | What's happening |
|---|---|
var Roster : []player = array{} |
Declares a mutable empty player array. The type annotation is required so Verse knows the element type. |
EnterTrigger.TriggeredEvent.Subscribe(OnPlayerEntered) |
Subscribes a class-scope method to the trigger's event. |
if (A := Agent?): |
Unwraps the ?agent option — mandatory before you can use the value. |
if (P := player[A]): |
Downcasts agent to player — a failable operation, hence inside if. |
set Roster += array{P} |
Appends P to the roster. += on arrays concatenates; wrapping P in array{P} makes it a single-element array to concatenate. |
Roster.Length |
Built-in property — returns the current element count as int. |
The for loop in OnPlayerLeft |
Manually filters the array because RemoveAllElements works on value types like int/float; for reference types like player you rebuild the array with a filter loop. |
Common patterns
Pattern 1 — Append multiple items at once (wave spawn list)
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
wave_spawn_tracker := class(creative_device):
@editable
SpawnPad1 : creature_placer_device = creature_placer_device{}
@editable
SpawnPad2 : creature_placer_device = creature_placer_device{}
@editable
SpawnPad3 : creature_placer_device = creature_placer_device{}
# Collects all spawn pads into one array for easy iteration.
var ActivePads : []creature_placer_device = array{}
OnBegin<override>()<suspends> : void =
# Append all three pads in one statement.
set ActivePads += array{SpawnPad1, SpawnPad2, SpawnPad3}
Print("Wave pads registered: {ActivePads.Length}")
# Iterate and spawn from every pad.
for (Pad : ActivePads):
Pad.SpawnCreature()
Key idea: You can append multiple elements in a single += by putting them all inside array{…}. The result is a new array with all three pads appended — no loop needed.
Pattern 2 — Remove by value with RemoveAllElements (score blocklist)
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
blocklist_score_device := class(creative_device):
# A list of forbidden score values — remove them before processing.
var RawScores : []int = array{10, 0, 25, 0, 30, 0, 15}
@editable
StartButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
StartButton.InteractedWithEvent.Subscribe(OnStart)
OnStart(Agent : agent) : void =
# Strip all zero entries (invalid/placeholder scores).
set RawScores = RawScores.RemoveAllElements(0)
var Total : int = 0
for (Score : RawScores):
set Total += Score
Print("Valid total score: {Total}")
Key idea: RemoveAllElements(Value) returns a new array with every matching element gone. You must set the variable to the returned array — the original is unchanged if you don't.
Pattern 3 — Remove a slice by index with Remove (trim a queue)
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
objective_queue_device := class(creative_device):
# Objective IDs queued up for the round.
var ObjectiveQueue : []int = array{1, 2, 3, 4, 5}
@editable
NextButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
NextButton.InteractedWithEvent.Subscribe(OnAdvance)
# Pops the first objective off the front of the queue.
OnAdvance(Agent : agent) : void =
if (Remaining := ObjectiveQueue.Remove[0, 0]):
# Remove[From, To] removes indices From..To inclusive.
# Remove[0,0] drops just the first element.
set ObjectiveQueue = Remaining
Print("Next objective queued. Remaining: {ObjectiveQueue.Length}")
else:
Print("Queue is empty!")
Key idea: Remove[From:int, To:int] is failable (uses [] brackets), so it must live inside an if or if (Result := …) expression. It removes the inclusive index range and returns the rest.
Gotchas
1. Arrays are value types — always set the result back
This is the #1 mistake beginners make:
# WRONG — the original array is unchanged
MyArray.RemoveAllElements(0)
# CORRECT — capture the new array
set MyArray = MyArray.RemoveAllElements(0)
Every array operation returns a new array. If you don't assign it, the change is silently discarded.
2. Remove is failable — it must be in a failure context
# WRONG — Remove[] outside a failure context is a compile error
set MyArray = MyArray.Remove[0, 0]
# CORRECT
if (Trimmed := MyArray.Remove[0, 0]):
set MyArray = Trimmed
Remove uses [] (square-bracket call syntax) because it can fail when the indices are out of range.
3. Empty array needs a type annotation
# WRONG — compiler cannot infer element type
var Bag := array{}
# CORRECT
var Bag : []player = array{}
Without at least one element or an explicit type, the compiler reports an error.
4. Appending a single item requires wrapping it in array{}
# WRONG — P is a player, not an []player
set Roster += P
# CORRECT
set Roster += array{P}
+= on arrays is array concatenation, not element insertion. Wrap the item.
5. RemoveAllElements works best on value types
RemoveAllElements uses value equality. It works perfectly for int, float, string, and other value types. For reference types like player or agent, equality comparison may not behave as expected — use a manual filter loop (as shown in the Walkthrough) to be safe.
6. Iterating while mutating
Never set an array inside a for loop that is iterating over that same array. Capture the loop's source into a local copy first:
Snapshot := MyArray # local copy — immutable snapshot
for (Item : Snapshot):
if (ShouldRemove(Item)):
set MyArray = MyArray.RemoveAllElements(Item)