Overview
for is not a device — it's a core Verse control-flow expression, and it is the single most useful tool for working with devices. Placed devices almost always come in groups (a row of teleporters along the shore, a handful of player spawners on the dock), and the players you serve arrive as arrays too. for lets you sweep across those collections and call a device method on each element.
Reach for for whenever you catch yourself thinking "...for every X, do Y": for every spawner, spawn a player; for every teleporter, activate the link; for every player in the damage volume, grant a point. It pairs naturally with Subscribe handlers — one event fires, and inside the handler a for loop fans that single signal out across many devices.
The shape is simple:
for (Item : SomeArray):
Item.DoSomething()
You can also filter mid-loop with a <decides> (failable) expression: for (X : Array, X.IsReady[]): only runs the body for the elements that pass. That combination — iterate, filter, act on a real device — is what this article teaches on a sunny cove.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
The moment: Players stand on a clifftop above a cel-shaded cove. When the round timer succeeds, we want to celebrate: sweep across a row of teleporter_devices and drop everyone onto the beach below, then hand each of them a point via a score_manager_device. One timer event, many devices — that's for.
using { /Fortnite.com/Devices }
# A clifftop-to-cove celebration: one timer success fans out across
# an array of teleporters and a score manager using `for`.
sunny_cove_finale := class(creative_device):
# The round timer that fires SuccessEvent when the beach party begins.
@editable
RoundTimer : timer_device = timer_device{}
# A row of teleporters placed along the clifftop edge.
# In the Details panel you add each placed teleporter to this array.
@editable
BeachTeleporters : []teleporter_device = array{}
# Hands out celebration points.
@editable
ScoreManager : score_manager_device = score_manager_device{}
OnBegin<override>()<suspends>:void =
# First: link every teleporter so players can return later.
# `for` sweeps the whole placed array in one pass.
for (Tele : BeachTeleporters):
Tele.Enable()
Tele.ActivateLinkToTarget()
# When the timer succeeds, run our celebration handler.
RoundTimer.SuccessEvent.Subscribe(OnTimerSuccess)
# SuccessEvent is a listenable(?agent) — the handler receives an optional agent.
OnTimerSuccess(MaybeAgent : ?agent) : void =
# Unwrap the optional agent. If someone triggered the timer, teleport
# exactly them; otherwise fall through to the whole array behaviour.
if (Agent := MaybeAgent?):
# Sweep every teleporter and send this agent to the cove,
# then award them a point.
for (Tele : BeachTeleporters):
Tele.Activate(Agent)
ScoreManager.Activate(Agent)```
**Line by line:**
- `@editable RoundTimer : timer_device = timer_device{}` — a bare `Device.Method()` fails with 'Unknown identifier', so every placed device must be an `@editable` field. This one holds the timer you drop in the level.
- `@editable BeachTeleporters : []teleporter_device = array{}` — the `[]` makes this an *array* of teleporters. In the Details panel you add each placed teleporter, and Verse sees them as one collection to loop over.
- In `OnBegin`, the first `for (Tele : BeachTeleporters):` walks each teleporter and calls `Enable()` and `ActivateLinkToTarget()` on it — two real teleporter methods, applied to every element with no repeated code.
- `RoundTimer.SuccessEvent.Subscribe(OnTimerSuccess)` wires the timer's success signal to our method. Subscription happens in `OnBegin`; the handler is a method at class scope.
- `OnTimerSuccess(MaybeAgent : ?agent)` matches the `listenable(?agent)` signature — the timer hands us an *optional* agent.
- `if (Agent := MaybeAgent?):` unwraps the option. Only inside this block do we have a real `agent`.
- The inner `for (Tele : BeachTeleporters): Tele.Activate(Agent)` fans the single success event out: every teleporter teleports the agent (they emerge at whichever cove destination is set), and `ScoreManager.Activate(Agent)` grants the celebration point.
## Common patterns
**Spawn everyone in from a row of spawners.** Loop the spawner array and call `Spawn`/`SpawnPlayer` on each — great for dropping a squad onto the dock at once.
```verse
dock_squad_spawner := class(creative_device):
# Player spawn pads placed along the dock.
@editable
DockSpawners : []player_spawner_device = array{}
OnBegin<override>()<suspends>:void =
# Enable every spawner in one sweep.
for (Pad : DockSpawners):
Pad.Enable()
# When any pad spawns someone, log it via the SpawnedEvent.
for (Pad : DockSpawners):
Pad.SpawnedEvent.Subscribe(OnSpawned)
OnSpawned(Agent : agent) : void =
# A fresh arrival on the dock — nothing else needed here,
# but you could grant an item or teleport them onward.
Agent.IsA[] # harmless no-op placeholder guard
Reward every player currently standing in a cove damage volume. GetAgentsInVolume() returns an array; for walks it and hands each occupant a point.
cove_zone_rewarder := class(creative_device):
# A shallow-water volume in the cove.
@editable
CoveVolume : damage_volume_device = damage_volume_device{}
# Awards points to occupants.
@editable
ScoreManager : score_manager_device = score_manager_device{}
# A timer whose success tells us to sweep the zone.
@editable
ScoreTimer : timer_device = timer_device{}
OnBegin<override>()<suspends>:void =
ScoreTimer.SuccessEvent.Subscribe(OnTick)
OnTick(MaybeAgent : ?agent) : void =
# Grab everyone standing in the cove right now and reward them all.
for (Occupant : CoveVolume.GetAgentsInVolume()):
ScoreManager.Activate(Occupant)
Filter while you loop. A for can carry a <decides> guard so the body only runs for elements that pass. Here we only re-link teleporters that are actually enabled, using the reference device's IsReferenced check as a per-agent filter.
referenced_teleporter_linker := class(creative_device):
# Teleporters lining the shore.
@editable
ShoreTeleporters : []teleporter_device = array{}
# Tracks the currently referenced hero player.
@editable
HeroRef : player_reference_device = player_reference_device{}
OnBegin<override>()<suspends>:void =
HeroRef.ActivatedEvent.Subscribe(OnHeroActivated)
OnHeroActivated(Agent : agent) : void =
# Only act if this agent is the one the reference device tracks.
if (HeroRef.IsReferenced[Agent]):
# Sweep every shore teleporter and send the hero across.
for (Tele : ShoreTeleporters):
Tele.Activate(Agent)
Gotchas
- A bare device call won't compile. You cannot loop over a device you never declared. Every device — even inside a
for— must first exist as an@editablefield on thecreative_deviceclass. An empty[]teleporter_device = array{}field is populated in the Details panel. ?agentevents must be unwrapped before you loop.timer_device.SuccessEventislistenable(?agent). The handler gets a?agent, not anagent— you mustif (Agent := MaybeAgent?):before passing it toTele.Activate(Agent). Skipping the unwrap is a type error.agentevents give you anagentdirectly.player_spawner_device.SpawnedEventandteleporter_device.EnterEventarelistenable(agent), so their handlers take a plainagent— no?unwrap. Don't confuse the two shapes.- A
forover an empty array simply does nothing. If your Details-panel array is empty, the loop body never runs — no error, no effect. If your beach stays quiet, check that the array actually contains placed devices. <decides>filters insideformust be failable calls. Methods likeIsReferenced[Agent]andIsInVolume[Agent]use square brackets and can fail; use them as loop guards or insideif, never as plain()statements.- No int/float mixing. If you ever compute a delay or count inside a loop, remember Verse never auto-converts — keep your counters
intand your timesfloatexplicitly.