Reference Verse compiles

Shuffle in Verse: Randomizing Arrays for Unpredictable Gameplay

Every time a player docks at your sun-drenched cove, the treasure chest order should feel fresh. Verse's built-in `Shuffle` function from `/Verse.org/Random` takes any array and returns a new array with the same elements in a random order — no manual Fisher-Yates needed. Master it once and every loot table, spawn sequence, and quiz question on your island becomes endlessly replayable.

Updated Examples verified on the live UEFN compiler
Watch the Knotshuffle_array in ~90 seconds.

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.

Build your own lesson with shuffle_array

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →