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, callingBombSpawner.Spawn()would fail with Unknown identifier.StatusText<localizes>(...)— the pattern for producing amessagevalue; raw strings won't compile where amessageis required.- In
OnBegin, each.Subscribe(...)wires one of the device's reallistenableevents to a class method. BombSpawner.Spawn()creates the carryable in-world at round start.OnBombSpawned()takes no parameters becauseSpawnEventislistenable(tuple()).OnBombPickedUp(Agent:agent)andOnBombThrown(Agent:agent)receive a plainagent— those events arelistenable(agent).BombSpawner.Explode(Agent)uses the overload that assigns an instigator, so the explosion is credited to the thrower.OnBombExploded(Instigator:?agent, Affected:[]agent)matchesExplodeEvent'slistenable(tuple(?agent, []agent))— note the optional instigator unwrapped withif (Who := Instigator?):.RespawnBombruns in aspawnblock so it canSleepwithout blocking, and guards withIsSpawned[]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
SpawnEventhas no agent. It'slistenable(tuple()), so its handler takes zero parameters —OnBombSpawned():void. Adding anagentparam won't match.ExplodeEvent's instigator is optional. The signature istuple(?agent, []agent). You must unwrap withif (Who := Instigator?):before using the agent; it can legitimately be empty.- Two
Explodeoverloads.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[]):orif (not Carryable.IsSpawned[]):. It returns nothing — its success or failure is the answer.ForcePlayerToCarrycan 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.message≠string. Any API taking amessageneeds a<localizes>helper; there is noStringToMessage. PlainPrinttakes astringand 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
@editablefield. A barecarryable_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 withIsSpawned[]keeps your respawn logic predictable.