Reference Devices

carryable_spawner_device: Pick-Up-and-Carry Objects in Verse

The carryable_spawner_device is your tool for any 'grab the bomb and run' or 'capture the relic' game loop. It spawns a physical object a player can pick up, carry, throw, and even detonate — and Verse lets you react to every one of those moments and drive the object's mesh, material, and explosions from code.

Updated
The code on this reference page is provided as-is and did not pass the latest compile check — treat the examples as a starting point and verify in your project.
Watch the Knotcarryable_spawner_device in ~90 seconds.

Overview

The carryable_spawner_device spawns a single physical object into the world that players can pick up, carry in their hands, drop, throw, and (optionally) explode. Think of the bomb in Search & Destroy, a glowing relic in a heist mode, or a payload your team must escort to a goal zone.

Reach for this device whenever your mode revolves around one object that changes hands. The device gives you events for every interaction — PickUpEvent, DropEvent, ThrowEvent, ReleaseEvent, SpawnEvent, ExplodeEvent, and AgentCollideEvent — and methods to control the object: Spawn, Despawn, Explode, ForcePlayerToCarry, plus runtime appearance swaps via SetCarryableMesh and SetCarryableMaterial.

Because it's a placed device, you control it from Verse by declaring it as an @editable field in your creative_device, then subscribing handlers in OnBegin.

API Reference

carryable_spawner_device

Used to spawn a carryable object into the experience.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).

carryable_spawner_device<public> := class<concrete><final>(creative_device_base, enableable):

Events (subscribe a handler to react):

Event Signature Description
SpawnEvent SpawnEvent<public>:listenable(tuple()) Signaled when the carryable spawns, either by the Spawn function, or by timer.
ExplodeEvent ExplodeEvent<public>:listenable(tuple(?agent, []agent)) Signaled when the carryable explodes. Returns the instigating agent, if one exists. * The agent provided to the Explode function, or the agent who dealt lethal damage to the carryable. * Otherwise, the agent who most recently carrie
PickUpEvent PickUpEvent<public>:listenable(agent) Signaled when agent picks up the carryable.
DropEvent DropEvent<public>:listenable(agent) Signaled when agent drops the carryable. Includes manual drop as well as force drop, which can occur on entering a state that doesn't support carrying, such as elimination.
ThrowEvent ThrowEvent<public>:listenable(agent) Signaled when agent throws the carryable.
ReleaseEvent ReleaseEvent<public>:listenable(agent) Signaled when agent stops carrying the carryable. This includes dropping, throwing, despawning, or force pickup by another player.
AgentCollideEvent AgentCollideEvent<public>:listenable(carryable_spawner_agent_impact_result) Signaled when the carryable collides with an agent. Damage applied is based off the collision velocity, as well as the device's Impact Damage settings. This event will fire even if the damage applied is 0.

Methods (call these to make the device act):

Method Signature Description
Spawn Spawn<public>():void Spawn the carryable from the device if it doesn't currently exist.
Despawn Despawn<public>():void Despawn the carryable, if it exists.
IsSpawned IsSpawned<public>()<reads><decides>:void Fails if the carryable does not exist in-world.
Explode Explode<public>():void Explode the carryable, if it exists.
Explode Explode<public>(Agent:agent):void Explode the carryable, if it exists. Assigns the provided agent as the explosion instigator.
ForcePlayerToCarry ForcePlayerToCarry<public>(Player:player):void Forces the carryable to be carried by the provided player, teleporting it into their hands. If not in a viable state to carry the item (such as in a vehicle), or if the player fails the device's filters, it is ignored.
SetCarryableMesh SetCarryableMesh<public>(Mesh:mesh):void Set the mesh of the carryable. This will update immediately if already spawned, and also apply to any carryable spawned from this device in the future.
SetCarryableMaterial SetCarryableMaterial<public>(Material:material, ?Index:int Set the material of the carryable. Index describes which material index on the mesh the material will apply to. This will update immediately if already spawned, and also apply to any carryable spawned from this device in the future.

Walkthrough

Let's build a bomb-carry objective. A bomb spawns in the middle of the map. When a player picks it up, we light them up with a status message. If they throw it, it explodes after impact. If anyone carries it onto a goal, we detonate it and respawn a fresh one — a full carry loop driven entirely by the device's real events and methods.

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

log_bomb := class(log_channel){}

bomb_carry_device := class(creative_device):

    # Drag your placed Carryable Spawner onto this slot in the Details panel.
    @editable
    BombSpawner : carryable_spawner_device = carryable_spawner_device{}

    # A localized message helper — message params never take raw strings.
    StatusText<localizes>(S:string):message = "{S}"

    OnBegin<override>()<suspends>:void =
        # Subscribe handlers to the device's real events.
        BombSpawner.SpawnEvent.Subscribe(OnBombSpawned)
        BombSpawner.PickUpEvent.Subscribe(OnBombPickedUp)
        BombSpawner.ThrowEvent.Subscribe(OnBombThrown)
        BombSpawner.ExplodeEvent.Subscribe(OnBombExploded)

        # Spawn the bomb when the round starts.
        BombSpawner.Spawn()

    # SpawnEvent hands us an empty tuple — no agent involved.
    OnBombSpawned():void =
        Print("A bomb has appeared in the arena!", ?Color := NamedColors.Yellow)

    # PickUpEvent hands us the agent who grabbed it.
    OnBombPickedUp(Agent:agent):void =
        Print("Bomb picked up — carry it to the goal!", ?Color := NamedColors.Orange)

    # ThrowEvent fires when the carrier throws it.
    OnBombThrown(Agent:agent):void =
        Print("Bomb thrown!", ?Color := NamedColors.Red)
        # Detonate it, crediting the thrower as instigator.
        BombSpawner.Explode(Agent)

    # ExplodeEvent gives us an optional instigator and the affected agents.
    OnBombExploded(Instigator:?agent, Affected:[]agent):void =
        if (Who := Instigator?):
            Print("Boom! Detonated by a player.", ?Color := NamedColors.Red)
        # Respawn a fresh bomb after a short pause so the loop continues.
        spawn{ RespawnBomb() }

    RespawnBomb()<suspends>:void =
        Sleep(3.0)
        # Only spawn if one isn't already in the world.
        if (not BombSpawner.IsSpawned[]):
            BombSpawner.Spawn()

Line by line:

  • @editable BombSpawner : carryable_spawner_device = carryable_spawner_device{} — the field you bind to your placed device. Without this, calling BombSpawner.Spawn() would fail with Unknown identifier.
  • StatusText<localizes>(...) — the pattern for producing a message value; raw strings won't compile where a message is required.
  • In OnBegin, each .Subscribe(...) wires one of the device's real listenable events to a class method.
  • BombSpawner.Spawn() creates the carryable in-world at round start.
  • OnBombSpawned() takes no parameters because SpawnEvent is listenable(tuple()).
  • OnBombPickedUp(Agent:agent) and OnBombThrown(Agent:agent) receive a plain agent — those events are listenable(agent).
  • BombSpawner.Explode(Agent) uses the overload that assigns an instigator, so the explosion is credited to the thrower.
  • OnBombExploded(Instigator:?agent, Affected:[]agent) matches ExplodeEvent's listenable(tuple(?agent, []agent)) — note the optional instigator unwrapped with if (Who := Instigator?):.
  • RespawnBomb runs in a spawn block so it can Sleep without blocking, and guards with IsSpawned[] so we never double-spawn.

Common patterns

Force a chosen player to carry the object

Great for a 'designated carrier' or relay race: when the bomb spawns, immediately shove it into the first player's hands with ForcePlayerToCarry.

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

force_carry_device := class(creative_device):

    @editable
    Carryable : carryable_spawner_device = carryable_spawner_device{}

    OnBegin<override>()<suspends>:void =
        Carryable.Spawn()
        # Grab the first player and force them to hold the object.
        AllPlayers := GetPlayspace().GetPlayers()
        if (First := AllPlayers[0]):
            Carryable.ForcePlayerToCarry(First)

React to drops and re-pickups (release tracking)

ReleaseEvent fires whenever a carrier stops carrying — drop, throw, despawn, or being stripped of it. Use it to track when the object is loose and up for grabs.

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

relay_device := class(creative_device):

    @editable
    Carryable : carryable_spawner_device = carryable_spawner_device{}

    OnBegin<override>()<suspends>:void =
        Carryable.DropEvent.Subscribe(OnDropped)
        Carryable.ReleaseEvent.Subscribe(OnReleased)
        Carryable.Spawn()

    OnDropped(Agent:agent):void =
        Print("Carrier dropped the payload!", ?Color := NamedColors.Orange)

    OnReleased(Agent:agent):void =
        # Fires on drop, throw, despawn, or forced steal.
        Print("Payload is loose — anyone can grab it.", ?Color := NamedColors.White)

Collision damage and live appearance swaps

AgentCollideEvent fires when the thrown object hits an agent. Combine it with SetCarryableMaterial to recolor the object as a 'hot' warning state.

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

impact_device := class(creative_device):

    @editable
    Carryable : carryable_spawner_device = carryable_spawner_device{}

    # Bind a material asset in the Details panel.
    @editable
    HotMaterial : material = material{}

    OnBegin<override>()<suspends>:void =
        Carryable.AgentCollideEvent.Subscribe(OnCollide)
        Carryable.Spawn()
        # Recolor the carryable immediately on the first material slot.
        Carryable.SetCarryableMaterial(HotMaterial, ?Index := 0)

    OnCollide(Result:carryable_spawner_agent_impact_result):void =
        Print("The carryable slammed into someone!", ?Color := NamedColors.Red)

Gotchas

  • SpawnEvent has no agent. It's listenable(tuple()), so its handler takes zero parameters — OnBombSpawned():void. Adding an agent param won't match.
  • ExplodeEvent's instigator is optional. The signature is tuple(?agent, []agent). You must unwrap with if (Who := Instigator?): before using the agent; it can legitimately be empty.
  • Two Explode overloads. Explode() detonates anonymously; Explode(Agent:agent) credits an instigator — use the latter when you want kill/objective credit to flow to a player.
  • IsSpawned[] is a failable query. It uses <decides>, so call it in a failure context: if (Carryable.IsSpawned[]): or if (not Carryable.IsSpawned[]):. It returns nothing — its success or failure is the answer.
  • ForcePlayerToCarry can silently no-op. If the player is in a vehicle, in an invalid state, or fails the device's configured filters, the call is simply ignored — there's no error. Don't assume the player is now holding the object.
  • messagestring. Any API taking a message needs a <localizes> helper; there is no StringToMessage. Plain Print takes a string and is fine for debugging, but it doesn't make the device do anything — call the device's real methods for game effects.
  • Declare the device as an @editable field. A bare carryable_spawner_device.Spawn() won't compile — you must reference the placed instance through your bound field.
  • Don't double-spawn. Spawn() only creates the object if one doesn't already exist, but guarding with IsSpawned[] keeps your respawn logic predictable.

Build your own lesson with carryable_spawner_device

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 →