ReferenceVerse

for-with-index: Looping Over Devices With Their Position in Line

Sometimes a plain for loop isn't enough — you need to know WHICH item you're on. The teleporter you fire, the score you grant, the delay before the next thing all depend on position in the line. Verse's index-and-value for loop hands you both at once, and on a sunny cove full of lined-up devices it's exactly the tool for the job.

Updated
The code on this reference page did not pass the latest compile check — verify it in your project.
Watch the Knot — for_with_index in ~90 seconds.

Overview

Picture a bright, cel-shaded cove: three teleporter pads sit in a neat row along the dock, and you want to light them up one after another — pad 0 first, then pad 1, then pad 2 — awarding a little more score for each pad the player reaches. A regular for (Pad : Pads) walks the array but never tells you where you are. That's the whole problem for-with-index solves.

for-with-index is not a device — it's a core Verse loop form. When you iterate an array, you can ask for the position alongside the element:

for (Index -> Value : MyArray):
    # Index is a zero-based int, Value is the element

Reach for it whenever the order matters: staggering delays, numbering players on a leaderboard, activating device number N, or granting points that scale with position. Because @editable []device fields let you drop a whole row of pads or scoreboards into one array in the UEFN details panel, for-with-index becomes the natural way to drive them all from one script.

API Reference

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

Walkthrough

Here's the full cove moment. A row of teleporter_devices and a matching row of score_manager_devices are wired into two arrays. When a player steps into the first teleporter, we loop the whole row with index: each teleporter links to its target, and each score manager is told to grant Index + 1 points (pad 0 → 1 point, pad 1 → 2 points, pad 2 → 3 points) by calling Increment that many times before Activate.

using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }

cove_relay := class(creative_device):

    # A row of teleporter pads dropped along the dock.
    @editable
    Teleporters : []teleporter_device = array{}

    # A matching row of score managers, one per pad.
    @editable
    Scorers : []score_manager_device = array{}

    # The pad the player steps into to kick everything off.
    @editable
    StartPad : teleporter_device = teleporter_device{}

    OnBegin<override>()<suspends>:void =
        # When someone enters the start pad, run the staggered activation.
        StartPad.EnterEvent.Subscribe(OnPlayerArrived)

    OnPlayerArrived(Agent : agent):void =
        # Walk the teleporter row WITH its index.
        for (Index -> Pad : Teleporters):
            # Every pad links back so the player can return.
            Pad.ActivateLinkToTarget()

            # Award points that scale with the pad's position.
            # Pad 0 gives 1 point, pad 1 gives 2, pad 2 gives 3...
            if (Scorer := Scorers[Index]):
                # Increment (Index + 1) times so the next Activate grants that many.
                for (Bump := 0..Index):
                    Scorer.Increment(Agent)
                Scorer.Activate(Agent)

Line by line:

  • @editable Teleporters : []teleporter_device = array{} declares an array field. In UEFN you drop each dock pad into a slot; the order in the panel becomes the index order here.
  • StartPad.EnterEvent.Subscribe(OnPlayerArrived) wires the trigger. EnterEvent is a listenable(agent), so the handler receives an agent directly.
  • for (Index -> Pad : Teleporters): is the star. Index is a zero-based int; Pad is the teleporter_device at that position. Both are available in one loop.
  • Pad.ActivateLinkToTarget() calls a real teleporter method on each pad so it can return the player later.
  • if (Scorer := Scorers[Index]): indexes the parallel array. Array indexing can fail (out of bounds), so it must be guarded with if — this fails gracefully if the two rows aren't the same length.
  • for (Bump := 0..Index): Scorer.Increment(Agent) uses the index as a count: it bumps the pending score by 1 for each step from 0 through Index, so higher pads award more.
  • Scorer.Activate(Agent) grants the accumulated points to the player.

Common patterns

Staggered cinematics — play sequence N after N seconds. The index becomes a delay, so a row of cinematic devices fires like a wave rolling down the shore.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

wave_cinematics := class(creative_device):

    @editable
    Sequences : []cinematic_sequence_device = array{}

    @editable
    Kickoff : teleporter_device = teleporter_device{}

    OnBegin<override>()<suspends>:void =
        Kickoff.EnterEvent.Subscribe(OnStart)

    OnStart(Agent : agent):void =
        spawn { PlayWave() }

    PlayWave()<suspends>:void =
        # Index gives each sequence its own delay before playing.
        for (Index -> Seq : Sequences):
            Sleep(Index * 1.0)
            Seq.Play()

Numbering a spawn line — spawn player N from spawner N. Loop players and spawners together, matching each player to the pad at the same index.

using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }

spawn_line := class(creative_device):

    @editable
    Spawners : []player_spawner_device = array{}

    @editable
    GoPad : teleporter_device = teleporter_device{}

    OnBegin<override>()<suspends>:void =
        GoPad.EnterEvent.Subscribe(OnGo)

    OnGo(Agent : agent):void =
        Players := GetPlayspace().GetPlayers()
        # Pair each player with the spawner at the same slot.
        for (Index -> P : Players):
            if (Spawner := Spawners[Index], FortP := player[P]):
                Spawner.SpawnPlayer(FortP)

Resetting a row of timers with a position-based label. Here the index just proves we visited each element in order while calling a real device method on each.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

timer_row := class(creative_device):

    @editable
    Timers : []timer_device = array{}

    @editable
    ResetPad : teleporter_device = teleporter_device{}

    OnBegin<override>()<suspends>:void =
        ResetPad.EnterEvent.Subscribe(OnReset)

    OnReset(Agent : agent):void =
        for (Index -> T : Timers):
            # First timer resets for the agent; the rest reset for all.
            if (Index = 0):
                T.Reset(Agent)
            else:
                T.ResetForAll()

Gotchas

  • Indexing a parallel array can fail. Scorers[Index] is a failable expression — if Scorers is shorter than Teleporters, it fails. Always guard with if (Scorer := Scorers[Index]):. Never assume two @editable arrays are the same length; a designer can leave a slot empty.
  • The index is always an int, and Verse won't auto-convert. If you want to use it as a float delay (Sleep), you must multiply by a float: Index * 1.0, not Index. Mixing int and float is a compile error.
  • Index -> Value order matters. The name before the arrow is the index/key; the name after is the value. Writing for (Pad -> Index : Teleporters) silently gives you an int where you expected a device — the compiler will complain when you call a device method on it.
  • EnterEvent hands you an agent, not a player. Methods like SpawnPlayer need a player, so unwrap with if (FortP := player[P]): before calling them. Don't force the raw agent in.
  • The loop body is a normal method, not a suspending context. If you need Sleep between iterations (staggered waves), the loop must run inside a <suspends> function that you spawn, as in the cinematics pattern — you can't Sleep directly inside a plain event handler.
  • Zero-based indexing. The first element is Index = 0. If you want human-friendly 'Pad 1, Pad 2', add 1 when you display or count — that's exactly why the walkthrough grants Index + 1 points.

Build your own lesson with for_with_index

Generate a personalized, compile-checked lesson grounded in this exact reference.

Build a lesson →