Tutorial 03 · World design

Keep players moving

If every resource point is always on, players camp the nearest one and never see the rest of your world. Instead, keep only a few of N nodes awake. Each one rotates on a timer or on first collection, whichever comes first, and its HUD marker follows it.

Draft · verify code before publishing
A resource node with its Beacon marker above it, seen in the editor
7steps, in build order
N of Mnodes awake at once
2ways a node rotates
1Verse file

Before step one

  • New to UEFN? Do tutorial 00: setup first. It covers the software, your Epic developer account and how to add a Verse file.
  • A world big enough that walking between points takes a while.
  • A Score Manager device: the download awards collected amounts as score. Want saved currency instead? Call GiveCurrency from tutorial 02's device.
  • A rough number: how many nodes in total, and how many awake at once.

Download the Verse files

Complete files used in this tutorial; each works on its own. How to add one: setup step 7. Build-check in UEFN pending.

Download all (.zip)
  • .vdropper_manager.verseRotating resource nodes: N of M awake, timer-or-collect rotation, beacon syncDownload
01

Place the nodes around the map

every node exists in the world, spread out and named

A node is a place players go to collect. Each one needs a trigger players can activate and something visible. Spread them so that no two awake nodes are ever next to each other.

What to place

  • A Trigger at each node location (players collect by activating it).
  • A Billboard showing the amount waiting, plus an Audio Player and VFX Spawner for feedback.
  • Names like resource_node_north_01, so they read well in arrays later.
Top-down map with all node positions marked
Done when

You can fly around the map in the editor and find every node by its name in the Outliner.

02

Give every node a Beacon

players can see where the awake nodes are from anywhere on the map

Use the native Beacon device, not a hand-built landmark. An earlier version of this project used a glowing static mesh on a pole: more work, looked worse, and it was hit by a bug where prop meshes silently disappear. The Beacon gives you a HUD icon, an off-screen arrow and a distance label for free.

PropertySet to
friendly Icon TextShort label, e.g. "Resource"
showOffscreenArrowOn
displayDistanceTextOn
beacon ColorOne colour for all nodes
In-game view with a node's Beacon icon floating above it
Done when

In a playtest with a beacon enabled, you can turn away from it and an arrow points you back.

03

Wire the nodes into the Verse device

the manager device knows every node and its beacon

The manager holds an @editable array Nodes; each entry pairs a node's trigger, billboard, sound, VFX and beacon. These are struct arrays, and they can only be filled by hand in the Details panel. Collecting awards the waiting amount as score through a Score Manager device, wired to ScoreManager.

Note

Every field in the node struct is one manual drag, times every node. Keep the struct small: trigger, beacon, and only what you really need.

Details panel with the node array filled: trigger and beacon per entry
Trap

An empty field in an entry doesn't error. That node simply never wakes up, or its beacon never shows.

Done when

Every array entry has both fields filled, and the count matches the nodes you placed in step 1.

04

Write the rotation loop

a node wakes, stays awake until timeout or collection, then sleeps and frees its slot

For each awake slot, a loop picks a sleeping node, enables it, and then waits for whichever comes first: the timer runs out or someone collects. race is the cleanest way to say that in Verse: the first branch to finish wins, the other is cancelled.

dropper_manager.verse — rotation loop (per slot)
loop:
    if (Idx := PickRandomInactiveNode()?):
        if (Node := Nodes[Idx]):
            # ... enable trigger, billboard, beacon, start the fill loop ...
            race:
                Sleep(RotateSeconds)       # timer ran out
                WaitForCollect(Idx, Node)  # or someone collected first
            # ... disable, put the node back to sleep ...
    else:
        Sleep(1.0)                         # nothing free right now, try again
dropper_manager.verseThe complete file, ready to paste into your project. Download full file
Done when

In a playtest, you stand still and watch awake nodes switch to other locations after RotateSeconds.

05

Keep markers honest

a beacon is on exactly when its node is awake

Enable the beacon in the same place you enable the node, and disable it in the same place you put it to sleep. A marker over a station that isn't active is worse than no marker at all: players run there for nothing and stop trusting the HUD.

Done when

You follow five beacons in a row during a playtest and every one leads to a node you can collect from.

06

Make the markers pausable from outside

another system (a concert, say) can hide every marker and the loop won't undo it

If you ever need to hide the markers temporarily, don't try to stop the loop. Set a flag and check it inside the loop, right where it enables beacons.

dropper_manager.verse — suppression flag
var SuppressMarkers : logic = false

SetMarkersHidden(Hidden : logic) : void =
    set SuppressMarkers = Hidden
    if (Hidden = true):
        for (Node : Nodes):
            Node.Beacon.Disable()
    else:
        for (Idx -> Node : Nodes):
            if (IsActive(Idx) = true):
                Node.Beacon.Enable()

# ...and inside the rotation loop:
if (SuppressMarkers = false):
    Node.Beacon.Enable()

In the download you don't call this yourself: wire HideMarkersTrigger and ShowMarkersTrigger to any trigger (for example the concert's start and end triggers).

Trap

Without the check inside the loop, the loop re-enables beacons a few seconds after you hid them, and the bug looks random.

Done when

You fire HideMarkersTrigger, wait longer than RotateSeconds, and no beacon has come back.

07

Playtest the rotation with people

players actually spread out across the map

Run a session with a few testers and just watch. You're checking two things: nodes rotate on collection, not only on the timer, and nobody ends up standing in one spot.

Done when

A tester collects from a node and, within a second, that node sleeps and another one wakes somewhere else.

Before you publish

Rotation checklist