Overview
A nested loop is simply a loop inside another loop. In Verse you have two main loop forms:
forexpression — iterates over a range or array, producing a value per element (or driving side effects).loop/break— runs indefinitely until abreakis hit, ideal for game-lifetime behaviors.
Nesting these lets you:
- Walk a 2-D grid of props (row × column) to hide/show platforms in a wave.
- Run an outer "round" loop with an inner "per-platform" loop that resets state each round.
- Stagger effects across a grid with
Sleep()between inner iterations.
Reach for nested loops whenever your game state has two independent axes — rounds × players, rows × columns, waves × items.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: A 3 × 3 Disappearing Platform Grid
You have nine creative_prop platforms arranged in a 3 × 3 grid. Each round, the grid hides platform-by-platform in row-major order (left-to-right, top-to-bottom), waits, then reveals them all at once before starting the next round. Players must jump between platforms that are still visible — classic floor-is-lava gameplay.
Setup in UEFN:
- Place nine props in a 3 × 3 layout and name them
Platform_00throughPlatform_22. - Create a Verse device and wire all nine props to the
@editablefields below. - Place the device in the level and hit Build Verse.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# A 3x3 grid of platforms that disappear row-by-column each round,
# then reappear together before the next round begins.
grid_disappear_device := class(creative_device):
# Wire these nine props in the Details panel — row 0
@editable
Platform00 : creative_prop = creative_prop{}
@editable
Platform01 : creative_prop = creative_prop{}
@editable
Platform02 : creative_prop = creative_prop{}
# Row 1
@editable
Platform10 : creative_prop = creative_prop{}
@editable
Platform11 : creative_prop = creative_prop{}
@editable
Platform12 : creative_prop = creative_prop{}
# Row 2
@editable
Platform20 : creative_prop = creative_prop{}
@editable
Platform21 : creative_prop = creative_prop{}
@editable
Platform22 : creative_prop = creative_prop{}
# Seconds between each individual platform disappearing
@editable
HideStagger : float = 0.4
# Seconds all platforms stay hidden before the round resets
@editable
HiddenDuration : float = 2.0
# Seconds all platforms stay visible before the next round
@editable
VisibleDuration : float = 3.0
# Build the grid as a 2-D array (array of rows, each row is an array of props)
GetGrid() : [][]creative_prop =
array:
array{Platform00, Platform01, Platform02}
array{Platform10, Platform11, Platform12}
array{Platform20, Platform21, Platform22}
OnBegin<override>()<suspends> : void =
# Outer loop: runs forever — one iteration = one round
loop:
# Make sure every platform is visible at the start of each round
transact:
for (Row : GetGrid(), Prop : Row):
Prop.Show()
# Give players time to position themselves
Sleep(VisibleDuration)
# --- NESTED LOOP: hide platforms one by one ---
# Outer for: iterate rows
transact:
for (Row : GetGrid()):
# Inner for: iterate columns within the current row
for (Prop : Row):
transact:
Prop.Hide() # Hide this single platform
Sleep(HideStagger) # Stagger: wait before hiding the next one
# All platforms are now hidden — hold the dramatic pause
Sleep(HiddenDuration)
# loop continues → next round begins```
**Line-by-line explanation:**
| Lines | What's happening |
|---|---|
| `GetGrid()` | Returns a `[][]creative_prop` — an array of rows, each row an array of props. This is the data structure the nested loops walk. |
| `loop:` | Outer infinite loop — one full iteration is one game round. |
| `for (Row : GetGrid(), Prop : Row): Prop.Show()` | Flattened double-for in one expression — shows every prop before each round. |
| `Sleep(VisibleDuration)` | Async pause: players see all platforms for `VisibleDuration` seconds. |
| `for (Row : GetGrid()):` | Outer `for` — steps through each row array. |
| `for (Prop : Row):` | **Inner `for`** — steps through each prop in the current row. |
| `Prop.Hide()` | Calls `creative_prop.Hide()` — hides the prop and disables its collision. |
| `Sleep(HideStagger)` | Yields for `HideStagger` seconds before hiding the next prop, creating a wave effect. |
| `Sleep(HiddenDuration)` | Dramatic pause while everything is hidden. |
## Common patterns
### Pattern 1 — Flat double-for (show all at once)
When you don't need a stagger between individual props, Verse lets you chain two iteration variables in a single `for` expression. This is the most concise way to touch every cell in a grid.
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# Flashes all platforms in a 2x3 grid on/off every few seconds.
flash_grid_device := class(creative_device):
@editable
Row0 : []creative_prop = array{}
@editable
Row1 : []creative_prop = array{}
@editable
OnDuration : float = 1.5
@editable
OffDuration : float = 1.5
GetGrid() : [][]creative_prop =
array{Row0, Row1}
OnBegin<override>()<suspends> : void =
loop:
# Single for expression with two variables — walks every cell
for (Row : GetGrid(), Prop : Row):
Prop.Hide()
Sleep(OffDuration)
for (Row : GetGrid(), Prop : Row):
Prop.Show()
Sleep(OnDuration)
Key point: for (Row : GetGrid(), Prop : Row) is Verse's flat nested iteration — both variables are bound in one for, and the body runs for every (Row, Prop) combination in row-major order.
Pattern 2 — Outer loop, inner for with random stagger
Use GetRandomFloat() inside the inner loop to give each platform a unique hide delay, making the grid feel organic rather than mechanical.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Random }
# Hides platforms in random order by randomizing the sleep between each hide.
random_stagger_device := class(creative_device):
@editable
PlatformRow0 : []creative_prop = array{}
@editable
PlatformRow1 : []creative_prop = array{}
@editable
PlatformRow2 : []creative_prop = array{}
@editable
MinStagger : float = 0.1
@editable
MaxStagger : float = 0.8
@editable
ResetDelay : float = 3.0
GetGrid() : [][]creative_prop =
array{PlatformRow0, PlatformRow1, PlatformRow2}
OnBegin<override>()<suspends> : void =
loop:
# Inner nested for: hide each prop after a random delay
for (Row : GetGrid()):
for (Prop : Row):
# Random stagger makes the grid feel alive
Delay := GetRandomFloat(MinStagger, MaxStagger)
Sleep(Delay)
Prop.Hide()
Sleep(ResetDelay)
# Restore all platforms before the next round
for (Row : GetGrid(), Prop : Row):
Prop.Show()
Sleep(1.0)
Pattern 3 — Outer round counter loop, inner per-row loop with increasing speed
Each round the stagger between hides shrinks, so the grid disappears faster as the game progresses. The outer loop tracks the round; the inner for drives the per-prop behavior.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# Escalating difficulty: each round the platform grid disappears faster.
escalating_grid_device := class(creative_device):
@editable
GridRows : [][]creative_prop = array{}
@editable
StartingStagger : float = 0.6
@editable
StaggerReduction : float = 0.05 # Subtracted each round
@editable
MinStagger : float = 0.05 # Floor so it never goes negative
@editable
HiddenPause : float = 2.0
@editable
VisiblePause : float = 2.5
OnBegin<override>()<suspends> : void =
var CurrentStagger : float = StartingStagger
loop:
# Show all platforms
for (Row : GridRows, Prop : Row):
Prop.Show()
Sleep(VisiblePause)
# Nested loops: outer = rows, inner = props in each row
for (Row : GridRows):
for (Prop : Row):
Prop.Hide()
Sleep(CurrentStagger)
Sleep(HiddenPause)
# Speed up next round — clamp to MinStagger
NextStagger := CurrentStagger - StaggerReduction
if (NextStagger > MinStagger):
set CurrentStagger = NextStagger
else:
set CurrentStagger = MinStagger
Gotchas
1. for in Verse is an expression, not a statement
for produces a value (an array of results). When you use it for side effects like Hide() or Show(), the result is []void — that's fine, just don't try to assign it expecting a meaningful array unless your body expression produces values.
2. Sleep() inside a nested for suspends the whole coroutine
Each Sleep(HideStagger) in the inner loop yields the coroutine for that many seconds. The outer loop iteration doesn't advance until the inner loop — including all its sleeps — finishes. This is usually what you want, but if you need rows to disappear in parallel, you need spawn for each row's inner loop.
3. loop never exits on its own — always plan your break
An infinite loop: without a break runs until the game session ends. For round-limited games, add a round counter and break when you hit the limit:
# Inside OnBegin<override>()<suspends>:void =
var Round : int = 0
loop:
set Round = Round + 1
if (Round > 5): break
# ... round logic
4. int and float do NOT auto-convert
Sleep() takes a float. If you compute a stagger from integer math (e.g., Round * 2), you must write Round * 2.0 or cast explicitly. Mixing int and float arithmetic is a compile error.
5. Editable arrays ([][]creative_prop) must be pre-populated
If you expose a [][]creative_prop as @editable, UEFN currently doesn't show a nested array editor well. The workaround used in Pattern 3 is to expose each row as a separate @editable []creative_prop field and assemble them in a GetGrid() helper method — exactly as shown in the Walkthrough.
6. creative_prop fields need real prop references
A bare creative_prop{} default is a null/unset prop. If you call Hide() or Show() on an unset prop at runtime, it silently does nothing (or errors). Always wire every @editable creative_prop field to a real placed prop in the UEFN Details panel before testing.