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.
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.EnterEventis alistenable(agent), so the handler receives anagentdirectly.for (Index -> Pad : Teleporters):is the star.Indexis a zero-basedint;Padis theteleporter_deviceat 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 withif— 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 throughIndex, 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 — ifScorersis shorter thanTeleporters, it fails. Always guard withif (Scorer := Scorers[Index]):. Never assume two@editablearrays 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, notIndex. Mixingintandfloatis a compile error. Index -> Valueorder matters. The name before the arrow is the index/key; the name after is the value. Writingfor (Pad -> Index : Teleporters)silently gives you anintwhere you expected a device — the compiler will complain when you call a device method on it.EnterEventhands you anagent, not aplayer. Methods likeSpawnPlayerneed aplayer, so unwrap withif (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
Sleepbetween iterations (staggered waves), the loop must run inside a<suspends>function that youspawn, as in the cinematics pattern — you can'tSleepdirectly 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 grantsIndex + 1points.
Build your own lesson with for_with_index
Generate a personalized, compile-checked lesson grounded in this exact reference.
Build a lesson →