Reference Verse

lives-system: Building a Custom Lives & Respawn Manager

While UEFN provides a native Lives System device, complex game modes often require programmatic control over life tracking, custom respawn delays, and dynamic game-over states. This guide teaches you how to build a robust, Verse-driven custom lives system using core concurrency and event subscription.

Updated

Overview

While Unreal Editor for Fortnite (UEFN) provides a native Lives System device for basic configuration, complex game modes often require programmatic control over life tracking, custom respawn delays, and dynamic game-over states. Because the native device's API surface is limited for Verse, this guide teaches you how to build a robust, Custom Lives System using core Verse concurrency (Sleep), state tracking (map), and event subscriptions (trigger_device).

API Reference

API Reference

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

Walkthrough

Let's build a "Lava Floor" damage zone. When a player steps on the trigger, they lose a life. If they have lives remaining, a coroutine handles a respawn delay using Sleep. If they hit zero lives, it triggers a game-over state.

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

custom_lives_device := class(creative_device):
    @editable
    DamageZone : trigger_device = trigger_device{}

    var PlayerLives : map(agent, int) = map{}
    const MaxLives : int = 3
    const RespawnDelay : float = 3.0

    OnBegin<override>()<suspends>:void =
        DamageZone.TriggeredEvent.Subscribe(OnPlayerDamaged)

    OnPlayerDamaged(Agent : ?agent):void =
        if (Player := Agent?):
            CurrentLives := GetLives(Player)
            NewLives := CurrentLives - 1

            if (NewLives <= 0):
                Print("Game Over for player!")
            else:
                Print("Player lost a life. Remaining: {NewLives}")
                set PlayerLives[Player] = NewLives
                spawn HandleRespawn(Player)

    HandleRespawn(Player : agent)<suspends>:void =
        Print("Respawning in {RespawnDelay} seconds...")
        Sleep(RespawnDelay)
        Print("Player respawned!")

    GetLives(Player : agent):int =
        if (Lives := PlayerLives[Player]):
            Lives
        else:
            MaxLives

Line-by-Line Breakdown:

  1. @editable DamageZone: Exposes the trigger to the UEFN UI so you can place it in the level.
  2. PlayerLives map: Tracks the current lives for each specific agent (player).
  3. OnBegin: Subscribes to the trigger's event when the simulation starts.
  4. if (Player := Agent?): Safely unwraps the optional ?agent provided by the event.
  5. spawn HandleRespawn: Kicks off a background coroutine so the respawn delay doesn't block other players from triggering the zone.
  6. Sleep(RespawnDelay): Pauses the coroutine for the specified float duration.

Common patterns

Pattern 1: The Reset Pad

A safe zone that restores a player's lives to the maximum when they step on it.

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

reset_lives_device := class(creative_device):
    @editable
    ResetPad : trigger_device = trigger_device{}

    var PlayerLives : map(agent, int) = map{}
    const MaxLives : int = 5

    OnBegin<override>()<suspends>:void =
        ResetPad.TriggeredEvent.Subscribe(OnReset)

    OnReset(Agent : ?agent):void =
        if (Player := Agent?):
            set PlayerLives[Player] = MaxLives

Pattern 2: Sudden Death Countdown

Using Sleep to create a dramatic countdown before a global elimination or life-loss event.

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

sudden_death_device := class(creative_device):
    @editable
    StartButton : button_device = button_device{}

    OnBegin<override>()<suspends>:void =
        StartButton.InteractedWithEvent.Subscribe(OnStartSuddenDeath)

    OnStartSuddenDeath(Agent : ?agent):void =
        if (Player := Agent?):
            spawn SuddenDeathCountdown()

    SuddenDeathCountdown()<suspends>:void =
        Print("Sudden Death in 3...")
        Sleep(1.0)
        Print("2...")
        Sleep(1.0)
        Print("1...")
        Sleep(1.0)
        Print("Elimination!")

Gotchas

  • Map Access Safety: In Verse, accessing a map key that doesn't exist will cause a runtime failure. Always use an if (Val := MyMap[Key]) block to safely unwrap the value, or provide a fallback as shown in the GetLives helper method.
  • Float vs Int in Sleep: The Sleep function requires a float. Passing an integer like Sleep(3) will cause a compile error. Always use a decimal point: Sleep(3.0).
  • Agent Unwrapping: Events like TriggeredEvent pass an optional agent (?agent). You must unwrap it using if (Player := Agent?) before you can use the player reference in your logic.
  • Localized Text for UI: If you decide to pass your life-count strings to a UI device (like a hud_message_device), you cannot pass a raw string. You must use a localized message type: MyText<localizes>(S:string):message = "{S}".

Build your own lesson with lives_system

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 →