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.