Arrays in Verse: Add, Remove, and Manage Collections
Tutorialbeginnercompiles

Arrays in Verse: Add, Remove, and Manage Collections

Updated beginnerDevicesCode verified

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:

  1. Append — set MyArray += array{NewItem} grows the array by one element.
  2. RemoveAllElements — removes every occurrence of a value, returning a new array.
  3. 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:

Get the complete code — free

You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.

Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.

Check your understanding

Test yourself with an interactive quiz and track your progress + earn XP — free for members.

Turn this into a guided course

Add How to build, grow, and shrink arrays at runtime in Verse for real game logic to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.

Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.

Comments

    Sign in to vote, comment, or suggest an edit.Sign in