Overview
The Shuffle function lives in the /Verse.org/Random module alongside GetRandomInt and GetRandomFloat. It solves a classic game-design problem: you have a fixed set of things, but you want players to encounter them in a different order every time.
Common uses on a Fortnite island:
- Randomize which item spawner activates first at a beach loot drop
- Shuffle the order of cinematic sequences in an intro cutscene
- Pick a random subset of score bonuses for a timed challenge
- Rotate which pressure plate triggers a vault door each round
Signature (from /Verse.org/Random):
Shuffle<public>(Input: []t where t: type)<transacts>: []t
Shuffle is a generic, pure function — it takes any typed array and returns a new shuffled array. The original array is unchanged. Because it is <transacts>, it can be called inside speculative (if) contexts without side effects.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: A sunny clifftop dock has four item spawners arranged along the pier. Each round, the spawners activate in a random order, one per second, so players can never memorise the loot pattern. A cinematic sequence plays after all spawners have fired.
using { /Fortnite.com/Devices }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
# Place this device on your island, then wire up the four @editable fields
# in the UEFN details panel.
dock_loot_shuffler := class(creative_device):
# Four item spawners placed along the clifftop pier
@editable
Spawner0 : item_spawner_device = item_spawner_device{}
@editable
Spawner1 : item_spawner_device = item_spawner_device{}
@editable
Spawner2 : item_spawner_device = item_spawner_device{}
@editable
Spawner3 : item_spawner_device = item_spawner_device{}
# Cinematic that plays after all loot has dropped
@editable
OutroCinematic : cinematic_sequence_device = cinematic_sequence_device{}
# Score manager awards a bonus for watching the full drop
@editable
BonusScore : score_manager_device = score_manager_device{}
OnBegin<override>()<suspends> : void =
# 1. Build an ordered array of all four spawners
Spawners : []item_spawner_device = array:
Spawner0
Spawner1
Spawner2
Spawner3
# 2. Shuffle returns a NEW array — original Spawners is untouched
ShuffledSpawners : []item_spawner_device = Shuffle(Spawners)
# 3. Activate each spawner in the shuffled order, one per second
for (S : ShuffledSpawners):
S.SpawnItem() # Spawn the item at this spawner's location
Sleep(1.0) # Wait 1 second before the next drop
# 4. All loot dropped — play the victory cinematic for everyone
OutroCinematic.Play()
# 5. Wait for the cinematic to finish, then award the score bonus
OutroCinematic.StoppedEvent.Await()
BonusScore.Activate()```
**Line-by-line breakdown:**
| Lines | What's happening |
|---|---|
| `Spawners := array{...}` | Collects the four `@editable` spawners into a typed `[]item_spawner_device`. |
| `Shuffle(Spawners)` | Returns a new array with the same four spawners in a random order. `Spawners` itself is unchanged. |
| `for (S : ShuffledSpawners)` | Iterates over every element in the shuffled result. |
| `S.Spawn()` | Calls the real `item_spawner_device` API to materialise the item in the world. |
| `Sleep(1.0)` | Suspends execution for one second so drops feel staggered, not simultaneous. |
| `OutroCinematic.Play()` | Fires the cinematic sequence device for all players. |
| `OutroCinematic.StoppedEvent.Await()` | Blocks until the cinematic ends before awarding score. |
| `BonusScore.Activate()` | Grants points via the score manager device. |
## Common patterns
### Pattern 1 — Shuffle a plain array of integers to pick a random question order
Useful for quiz minigames on your island where you have a fixed bank of questions stored as indices.
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
quiz_order_device := class(creative_device):
# One score manager per correct answer slot (5 questions)
@editable
Q0Score : score_manager_device = score_manager_device{}
@editable
Q1Score : score_manager_device = score_manager_device{}
@editable
Q2Score : score_manager_device = score_manager_device{}
# Helper: returns the score device for a given question index
GetScoreDevice(Index : int) : score_manager_device =
if (Index = 0):
Q0Score
else if (Index = 1):
Q1Score
else:
Q2Score
OnBegin<override>()<suspends> : void =
# Build an index array [0, 1, 2] then shuffle it
QuestionIndices : []int = array{0, 1, 2}
ShuffledIndices : []int = Shuffle(QuestionIndices)
# Activate score devices in the shuffled order with a 3-second gap
for (Idx : ShuffledIndices):
Device := GetScoreDevice(Idx)
Device.Enable()
Sleep(3.0)
Device.Disable()
Pattern 2 — Re-shuffle every round using a timer device
The timer fires at the end of each round; subscribe to SuccessEvent to trigger a fresh shuffle.
using { /Fortnite.com/Devices }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
repeating_shuffle_device := class(creative_device):
@editable
RoundTimer : timer_device = timer_device{}
@editable
SpawnerA : item_spawner_device = item_spawner_device{}
@editable
SpawnerB : item_spawner_device = item_spawner_device{}
@editable
SpawnerC : item_spawner_device = item_spawner_device{}
# Called each time the round timer succeeds
OnRoundEnd(MaybeAgent : ?agent) : void =
# Shuffle the spawners and fire the first one immediately
Spawners : []item_spawner_device = array{SpawnerA, SpawnerB, SpawnerC}
ShuffledSpawners : []item_spawner_device = Shuffle(Spawners)
if (First := ShuffledSpawners[0]):
First.Spawn()
OnBegin<override>()<suspends> : void =
# Subscribe so every timer completion triggers a new shuffle
RoundTimer.SuccessEvent.Subscribe(OnRoundEnd)
# Start the first round
RoundTimer.Start()
# Keep the device alive
loop:
Sleep(60.0)
Pattern 3 — Shuffle cinematic sequences for a randomised intro at the cove dock
Three short cinematics play in a random order each time a player arrives, keeping the atmosphere fresh.
using { /Fortnite.com/Devices }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
cove_intro_device := class(creative_device):
@editable
Intro0 : cinematic_sequence_device = cinematic_sequence_device{}
@editable
Intro1 : cinematic_sequence_device = cinematic_sequence_device{}
@editable
Intro2 : cinematic_sequence_device = cinematic_sequence_device{}
# Plays all three intros in a random order, waiting for each to finish
PlayShuffledIntros()<suspends> : void =
Intros : []cinematic_sequence_device = array{Intro0, Intro1, Intro2}
ShuffledIntros : []cinematic_sequence_device = Shuffle(Intros)
for (Seq : ShuffledIntros):
Seq.Play()
Seq.StoppedEvent.Await()
OnBegin<override>()<suspends> : void =
PlayShuffledIntros()
Gotchas
1. Shuffle returns a new array — it does NOT mutate the original
# WRONG mental model:
Shuffle(MyArray) # result is discarded — MyArray is unchanged!
# CORRECT:
Shuffled := Shuffle(MyArray) # capture the return value
Always assign the result to a new variable.
2. Indexing the shuffled result can fail — use if to unwrap
Array access in Verse is a failable expression. Always guard it:
if (First := ShuffledSpawners[0]):
First.Spawn()
# Without the `if`, the compiler will reject the bare index access
# in a non-failable context.
3. Shuffle requires the /Verse.org/Random import
Forgetting the import causes an Unknown identifier error:
using { /Verse.org/Random } # required — Shuffle lives here
4. The element type must be consistent — no mixed arrays
Shuffle is generic over t : type. All elements must be the same type. You cannot shuffle []item_spawner_device and []cinematic_sequence_device in the same call — create separate arrays for each device type.
5. Sleep inside a for loop requires <suspends> on the enclosing function
If you call Sleep while iterating a shuffled array, the function must be declared ()<suspends>. OnBegin already carries this effect, but any helper you extract must also declare it:
ActivateInOrder(Devices : []item_spawner_device)<suspends> : void =
for (D : Devices):
D.Spawn()
Sleep(1.0)
6. Shuffle is <transacts> — safe inside speculative contexts
Because Shuffle is marked <transacts>, you can call it inside an if block or other speculative context and rely on automatic rollback if the context fails. This is rarely needed but good to know.