Reference Verse compiles

Player Position: Distance to the Finish Line

Every racer, prop, and checkpoint on your island has a world position you can read from Verse: `GetTransform().Translation` hands you a `vector3`, and `Distance()` measures the gap between any two of them. This lesson turns those two calls into the finish-line proximity check and nearest-checkpoint helper that Barnaby's Jungle Mod-Rally uses to crown its winner — vector math with a dirtbike attached.

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

Overview

The Player Reference device (player_reference_device) solves a common island-design problem: how do I write Verse code that cares about one particular player? Whether you need to spotlight the current race leader, grant a bounty target special effects, or check if the agent who just stepped on a plate is the designated VIP, this device gives you the answer.

Key capabilities:

  • IsReferenced(Agent) — a failable (<decides>) check: succeeds only when Agent is the player currently stored in the device.
  • GetStatValue() — returns the integer stat the device is configured to track (kills, score, etc.).
  • Activate() — programmatically fires the device (useful for chaining logic).
  • EventsActivatedEvent, AgentUpdatedEvent, AgentReplacedEvent, AgentUpdateFailsEvent let you react whenever the stored reference changes.

Reach for this device whenever your game needs a named player slot that Verse code can interrogate or subscribe to.

API Reference

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

Walkthrough

Scenario — Bounty Board: A trigger plate marks whoever steps on it as the "Bounty Target." Every other player is notified. A second trigger checks whether the agent who steps on it is the bounty target and, if so, activates the device to signal a bounty-claimed event.

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

# Localized helper so we can pass message-typed params
bounty_msg<localizes>(S : string) : message = "{S}"

bounty_board_device := class(creative_device):

    # Drop this Player Reference device into the level and wire it here
    @editable
    BountySlot : player_reference_device = player_reference_device{}

    # Trigger plate that SETS the bounty target (step on it to become the target)
    @editable
    SetBountyPlate : trigger_device = trigger_device{}

    # Trigger plate that CLAIMS the bounty (only works for the current target)
    @editable
    ClaimBountyPlate : trigger_device = trigger_device{}

    # Called when the bounty reference slot is updated
    OnBountyUpdated(NewTarget : agent) : void =
        Print("Bounty target updated!")

    # Called when someone steps on the Set-Bounty plate
    OnSetBountyTriggered(Instigator : ?agent) : void =
        if (A := Instigator?):
            # Activate the device so it stores this agent as the reference
            BountySlot.Activate()
            Print("New bounty target designated.")

    # Called when someone steps on the Claim-Bounty plate
    OnClaimBountyTriggered(Instigator : ?agent) : void =
        if (A := Instigator?):
            # IsReferenced<decides> — only succeeds if A is the stored bounty target
            if (BountySlot.IsReferenced[A]):
                Print("Bounty claimed! Activating reward sequence.")
                BountySlot.Activate()   # signal downstream devices
            else:
                Print("Not the bounty target — keep hunting.")

    OnBegin<override>()<suspends> : void =
        # Subscribe to plate triggers
        SetBountyPlate.TriggeredEvent.Subscribe(OnSetBountyTriggered)
        ClaimBountyPlate.TriggeredEvent.Subscribe(OnClaimBountyTriggered)

        # Subscribe to reference-slot events
        BountySlot.AgentUpdatedEvent.Subscribe(OnBountyUpdated)
        BountySlot.AgentReplacedEvent.Subscribe(OnBountyUpdated)

        # Keep the device alive for the whole session
        loop:
            Sleep(60.0)

Line-by-line highlights:

  • BountySlot.IsReferenced[A] — the square-bracket call syntax is required for <decides> functions inside an if expression. It fails (branches to else) when A is not the stored player.
  • BountySlot.Activate() — tells the device to fire its ActivatedEvent and push its stored agent downstream to any wired devices.
  • AgentUpdatedEvent.Subscribe(OnBountyUpdated) — fires whenever the slot's stored agent changes to a new agent.
  • AgentReplacedEvent.Subscribe(OnBountyUpdated) — fires when the stored agent is replaced by a different one; subscribing to both covers all update paths.
  • The loop { Sleep(60.0) } keeps OnBegin suspended so subscriptions stay alive for the entire session.

Common patterns

Pattern 1 — Read the tracked stat and display it

Use GetStatValue() to pull the integer stat the device is configured to track (e.g., eliminations) and act on it — here, granting a bonus when the target reaches 5 kills.

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

stat_reward_device := class(creative_device):

    @editable
    BountySlot : player_reference_device = player_reference_device{}

    @editable
    RewardGranter : item_granter_device = item_granter_device{}

    # Poll the stat every 5 seconds and reward at threshold
    OnBegin<override>()<suspends> : void =
        loop:
            Sleep(5.0)
            CurrentKills := BountySlot.GetStatValue()
            Print("Bounty target kill count: {CurrentKills}")
            if (CurrentKills >= 5):
                # Grant the stored agent a bonus item
                if (StoredAgent := BountySlot.ActivatedEvent):
                    # Activate fires ActivatedEvent with the stored agent
                    BountySlot.Activate()
                Print("Threshold reached — granting bonus item.")
                RewardGranter.GrantItem()

Note: GetStatValue() returns the raw integer configured in the device's properties panel (Stat Type, Stat Source). Make sure the panel is set to the stat you actually want to track.

Pattern 2 — React to reference-slot events

Subscribe to ActivatedEvent to run logic the moment the device fires — for example, teleporting the stored agent to a boss arena.

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

boss_arena_device := class(creative_device):

    @editable
    BountySlot : player_reference_device = player_reference_device{}

    @editable
    ArenaTelepad : teleporter_device = teleporter_device{}

    # Fires when the device is activated (stores the agent at that moment)
    OnBountyActivated(StoredAgent : agent) : void =
        # Teleport the designated agent into the boss arena
        ArenaTelepad.Teleport(StoredAgent)
        Print("Bounty target teleported to boss arena!")

    OnBegin<override>()<suspends> : void =
        BountySlot.ActivatedEvent.Subscribe(OnBountyActivated)
        loop:
            Sleep(30.0)

Pattern 3 — Guard any action behind IsReferenced

Use IsReferenced as a gate so that only the designated player can open a vault door.

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

vault_guard_device := class(creative_device):

    @editable
    VIPSlot : player_reference_device = player_reference_device{}

    @editable
    VaultButton : button_device = button_device{}

    @editable
    VaultDoor : mutator_zone_device = mutator_zone_device{}

    OnButtonPressed(Instigator : agent) : void =
        # Only the VIP stored in VIPSlot may open the vault
        if (VIPSlot.IsReferenced[Instigator]):
            VaultDoor.Enable()
            Print("VIP opened the vault!")
        else:
            Print("Access denied — you are not the VIP.")

    OnBegin<override>()<suspends> : void =
        VaultButton.InteractedWithEvent.Subscribe(OnButtonPressed)
        loop:
            Sleep(60.0)

Gotchas

  1. IsReferenced is <decides> — use square brackets inside if. Call it as if (VIPSlot.IsReferenced[Agent]):, not VIPSlot.IsReferenced(Agent). The parenthesis form won't compile inside a conditional context because the failure mode is unhandled.

  2. The device must be @editable on a class(creative_device). Declaring var Slot := player_reference_device{} as a local variable and calling methods on it does nothing — the device must be placed in the level and referenced via an @editable field so the runtime wires it to the actual placed instance.

  3. Activate() stores the triggering agent, not a Verse-chosen one. You cannot pass an agent directly to Activate(). The device captures whoever triggered it via its in-editor wiring or the last player to interact with a wired input device. If you need to designate a specific agent from Verse, wire a trigger or button to the device in the editor and fire that trigger from code instead.

  4. GetStatValue() reflects the panel configuration. If the device's Stat Type is set to "None" in the properties panel, GetStatValue() always returns 0. Double-check the panel before debugging why your stat logic never fires.

  5. Subscribe to both AgentUpdatedEvent and AgentReplacedEvent for full coverage. AgentUpdatedEvent fires when the slot was empty and gets a new agent. AgentReplacedEvent fires when one agent is swapped for another. Missing either means your handler silently skips some update paths.

  6. No intfloat auto-conversion. GetStatValue() returns int. If you compare it to a float literal or pass it to a function expecting float, you must cast explicitly (e.g., Float(CurrentKills)).

Guides & scripts that use player_position

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

Build your own lesson with player_position

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 →