Reference Verse compiles

ranges in Verse: Measuring Distance on Your Island

Ranges in Verse come in two flavours: the built-in `range` type that iterates over a series of integers (like `0..4`), and float fields named `Range` that appear on weapon and AI components to express a distance in centimetres. Knowing which one you need — and how to use each — is the key to writing clean, distance-aware island logic. In this article you'll build a sunny dock scenario where a guard's visibility range gates whether a player can sneak past, and a for-loop over an integer range lig

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

Overview

The word range in UEFN Verse covers two related but distinct ideas:

  1. Integer range expressions — the range type, written Min..Max, that lets you iterate over a contiguous series of integers with a for loop. This is a core Verse language feature, not a device.
  2. Float Range fields — distance values (in centimetres) that appear on weapon components (e.g. fort_trace_weapon_component) and AI devices (e.g. guard_spawner_device.VisibilityRange). These control how far a mechanic reaches in 3-D space.

When to reach for each

You want to… Use…
Loop over indices 0 to N for (I := 0..N-1)
Activate N devices in sequence integer range + array index
Set how far a guard can see GuardSpawner.VisibilityRange (float)
Tweak weapon effective distance fort_trace_weapon_component.Range (float)

Both ideas show up constantly in real island scripting, so this article covers both with a concrete dock/shore scenario.

API Reference

(API surface could not be resolved for this device.)

Walkthrough

The scenario

You're building a Smuggler's Dock island. A row of five warning buoys lines the pier. When the round starts, the buoys light up one by one (integer range loop), and a guard spawner's visibility range is set based on whether it's day or night — wide open during the day, tighter at night so players can sneak past.

Level setup

  • Place 5 × Conditional Button devices (used here as buoy-light proxies) and wire them into the BuoyLights array.
  • Place 1 × Guard Spawner device and assign it to DockGuard.
  • Place 1 × Class Selector device (acts as the day/night toggle) assigned to DayNightToggle.
using { /Fortnite.com/Devices }
using { /Fortnite.com/AI }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

# smugglers_dock_controller — lights up buoys one by one, then sets guard
# visibility range based on time of day.
dock_controller := class(creative_device):

    # Five buoy-light devices placed along the pier.
    @editable
    BuoyLights : []button_device = array{}

    # The guard spawner watching the dock.
    @editable
    DockGuard : guard_spawner_device = guard_spawner_device{}

    # Class selector used as a day/night toggle.
    # When option A is chosen = day; option B = night.
    @editable
    DayNightToggle : class_and_team_selector_device = class_and_team_selector_device{}

    # Visibility range (cm) during the day — guards spot players at 15 m.
    DayVisibilityRange : float = 1500.0

    # Visibility range (cm) at night — only 6 m, perfect for sneaking.
    NightVisibilityRange : float = 600.0

    # Track whether it is currently daytime.
    var IsDaytime : logic = true

    OnBegin<override>()<suspends> : void =
        # Subscribe to the day/night toggle so we can react to changes.
        DayNightToggle.ClassSwitchedEvent.Subscribe(OnTimeOfDayChanged)

        # Light up the buoys one by one using an integer range.
        # 0..4 produces the integers 0, 1, 2, 3, 4 — one per buoy.
        for (Index := 0..4):
            if (Light := BuoyLights[Index]):
                Light.Enable()   # turn the buoy light on
            Sleep(0.4)           # brief pause for a ripple effect

        # Apply the starting (daytime) visibility range to the guard.
        ApplyVisibilityRange()

        # Spawn the guard now that the scene is set.
        DockGuard.Enable()

    # Called whenever the day/night class selector fires.
    OnTimeOfDayChanged(Agent : agent) : void =
        # Toggle the time-of-day flag.
        if (IsDaytime?):
            set IsDaytime = false
        else:
            set IsDaytime = true
        ApplyVisibilityRange()

    # Push the correct float Range value to the guard spawner.
    ApplyVisibilityRange() : void =
        if (IsDaytime?):
            # Daytime — guards have a long sight line across the sunny dock.
            set DockGuard.VisibilityRange = DayVisibilityRange
        else:
            # Night — reduced range lets players sneak along the shore.
            set DockGuard.VisibilityRange = NightVisibilityRange```

### Line-by-line explanation

| Lines | What's happening |
|---|---|
| `@editable BuoyLights` | An array of `button_device` — each represents one buoy light on the pier. |
| `@editable DockGuard` | The `guard_spawner_device` whose `VisibilityRange` float field we'll mutate. |
| `for (Index := 0..4)` | **Integer range**  Verse iterates Index through 0, 1, 2, 3, 4. |
| `BuoyLights[Index]` | Array subscript using the range index; returns `?button_device`, unwrapped with `if`. |
| `Sleep(0.4)` | Suspends the coroutine briefly so lights appear to ripple outward. |
| `set DockGuard.VisibilityRange = DayVisibilityRange` | Writes the **float Range field**  1500 cm = 15 m of guard sight. |
| `DockGuard.Enable()` | Spawns the guard after the scene is ready. |

## Common patterns

### Pattern 1 — Counting down with a reverse integer range

A countdown timer that ticks from 5 to 1 before the boat leaves the dock.

```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

dock_countdown := class(creative_device):

    @editable
    HudMessage : hud_message_device = hud_message_device{}

    CountdownText<localizes>(N : int) : message = "Boat leaves in {N}..."

    OnBegin<override>()<suspends> : void =
        # Iterate 5 down to 1 using a range and array reverse trick.
        # Verse ranges are always ascending, so we subtract from 5.
        for (Step := 0..4):
            Remaining := 5 - Step
            HudMessage.SetText(CountdownText(Remaining))
            HudMessage.Show()
            Sleep(1.0)
        HudMessage.Hide()

Why 0..4 and not 5..1? Verse integer ranges are always ascending5..1 produces no iterations. Subtract from your max value to count down.


Pattern 2 — Tightening a guard's visibility range progressively (float Range)

As a fog-of-war storm rolls in from the sea, the guard's sight line shrinks every 10 seconds.

using { /Fortnite.com/Devices }
using { /Fortnite.com/AI }
using { /Verse.org/Simulation }

fog_controller := class(creative_device):

    @editable
    ShoreGuard : guard_spawner_device = guard_spawner_device{}

    # Start at 2000 cm (20 m), shrink by 300 cm each tick, floor at 400 cm.
    OnBegin<override>()<suspends> : void =
        # Use an integer range to drive 6 fog-thickening steps (0..5).
        for (Step := 0..5):
            NewRange : float = 2000.0 - (300.0 * Step)
            # Clamp so we never go below 400 cm — guards still notice
            # players right next to them even in thick fog.
            ClampedRange : float =
                if (NewRange >= 400.0) then NewRange else 400.0
            set ShoreGuard.VisibilityRange = ClampedRange
            Sleep(10.0)

This pattern combines both range ideas: an integer range drives the loop steps, and a float VisibilityRange field is updated each iteration.


Pattern 3 — Iterating a range to reset multiple devices

After a round ends at the clifftop arena, reset all five capture pads in one clean loop.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

clifftop_reset := class(creative_device):

    @editable
    CapturePads : []capture_area_device = array{}

    @editable
    RoundEndTrigger : trigger_device = trigger_device{}

    OnBegin<override>()<suspends> : void =
        RoundEndTrigger.TriggeredEvent.Subscribe(OnRoundEnd)

    OnRoundEnd(Agent : ?agent) : void =
        # Reset every capture pad using a range over the array length.
        LastIndex := CapturePads.Length - 1
        if (LastIndex >= 0):
            for (I := 0..LastIndex):
                if (Pad := CapturePads[I]):
                    Pad.Reset()

Gotchas

1. Verse ranges are always ascending

Writing 5..1 compiles but produces zero iterations — the loop body never runs. To count downward, iterate 0..N and compute N - Index inside the body.

2. Integer range vs. float Range — completely different things

0..4 is a language-level iterator. guard_spawner_device.VisibilityRange is a var float field on a device. They share a name in English but have no connection in the type system. Don't try to assign a range expression to a float field.

3. VisibilityRange is clamped by the engine

The guard spawner clamps VisibilityRange between 0.0 and 25000.0 cm. Values outside that window are silently clamped — you won't get a compile or runtime error, the value just won't go higher than 250 m.

4. Array subscript returns an option

BuoyLights[Index] has type ?button_device. Always unwrap it:

if (Light := BuoyLights[Index]):
    Light.SetEnabled(true)

Skipping the if is a compile error — Verse won't let you call methods on an option type directly.

5. Sleep requires <suspends>

Any function that calls Sleep must be marked <suspends> (or called from one). OnBegin is already suspending; handler methods called via Subscribe are not — move long-running logic into a separate <suspends> task spawned with spawn{}.

6. Int ↔ Float conversion is explicit

Verse will not auto-convert. If your loop index Step is an int and you need it as a float for arithmetic, write (Step * 1.0) or cast explicitly — otherwise you'll get a type-mismatch compile error.

Guides & scripts that use ranges

Step-by-step tutorials that put this object to work.

Build your own lesson with ranges

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 →