Overview
The Creature Spawner device spawns one or more waves of creatures (Fortnite "fiends" and other creature types) at configurable intervals. While most of its behavior is configured in the device's Details panel, Verse gives you precise, event-driven control: you can enable/disable the faucet, spawn a creature at an exact world position, listen for spawns and eliminations, wipe all spawned creatures, and even destroy the spawner itself.
Reach for this device when you want a survival arena, a horde-mode wave that starts when players step on a plate, a boss room that floods with enemies, or any scenario where creatures need to appear and be cleaned up under script control.
Key ideas you'll use:
SpawnAt(...)is<suspends>— it takes time to load the creature, so it must be called from an async context and returns a?agentyou unwrap.SpawnedEventandEliminatedEventlet you score kills, track counts, and chain logic.GetSpawnLimit()tells you the device's configured cap so you don't spawn into a wall.
API Reference
creature_spawner_device
Used to spawn one or more waves of creatures of customizable types at selected time intervals.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
creature_spawner_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
SpawnedEvent |
SpawnedEvent<public>:listenable(agent) |
Signaled when a creature is spawned. Sends the agent creature who was spawned. |
EliminatedEvent |
EliminatedEvent<public>:listenable(device_ai_interaction_result) |
Signaled when a creature is eliminated. Source is the agent that has eliminated the creature. If the creature was eliminated by a non-agent then Source is 'false'. Target is the creature that was eliminated. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
SpawnAt |
SpawnAt<public>(Position:(/Verse.org/SpatialMath:)vector3, ?Rotation:?(/Verse.org/SpatialMath:)rotation |
Spawn a creature at the given position. When Rotation is not provided, it will default to the Device's rotation. Returns the agent spawned or false if the device has reached its maximum spawn count. This function is <suspends> because it |
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
DestroySpawner |
DestroySpawner<public>():void |
Destroys this device. |
EliminateCreatures |
EliminateCreatures<public>():void |
Eliminates all creatures spawned by this device. |
GetSpawnLimit |
GetSpawnLimit<public>()<transacts>:int |
Returns the spawn limit of the device. |
Walkthrough
Let's build a horde arena: when a player steps on a trigger plate, we enable the spawner, manually spawn an extra wave at a fixed position, count kills, and once the spawn limit's worth of creatures are eliminated we eliminate any stragglers and disable the device.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
using { /UnrealEngine.com/Temporary/Diagnostics }
horde_arena := class(creative_device):
# Drag your Creature Spawner device here in the Details panel.
@editable
Spawner : creature_spawner_device = creature_spawner_device{}
# The plate players step on to start the horde.
@editable
StartPlate : trigger_device = trigger_device{}
# How many creatures have been eliminated this round.
var Eliminated : int = 0
OnBegin<override>()<suspends>:void =
# React to spawns and kills.
Spawner.SpawnedEvent.Subscribe(OnCreatureSpawned)
Spawner.EliminatedEvent.Subscribe(OnCreatureEliminated)
# Start the horde when a player steps on the plate.
StartPlate.TriggeredEvent.Subscribe(OnPlateStepped)
# Begin with the faucet off.
Spawner.Disable()
OnPlateStepped(Agent : ?agent):void =
# Turn the faucet on so the device's own waves begin.
Spawner.Enable()
# Also drop one bonus creature right at the device, asynchronously.
spawn { SpawnBonusWave() }
SpawnBonusWave()<suspends>:void =
Limit := Spawner.GetSpawnLimit()
Print("Spawn limit is {Limit}")
# SpawnAt suspends while the creature loads; it returns ?agent.
MaybeCreature := Spawner.SpawnAt(vector3{ Forward := 0.0, Left := 0.0, Up := 200.0 })
if (Creature := MaybeCreature?):
Print("Bonus creature spawned!")
OnCreatureSpawned(Creature : agent):void =
Print("A creature joined the fight.")
OnCreatureEliminated(Result : device_ai_interaction_result):void =
set Eliminated = Eliminated + 1
Print("Eliminated count: {Eliminated}")
# Source is the agent that got the kill (false if non-agent).
if (Killer := Result.Source?):
Print("A player scored a kill.")
# Once we've cleared a spawn-limit's worth, end the horde.
if (Eliminated >= Spawner.GetSpawnLimit()):
Spawner.EliminateCreatures()
Spawner.Disable()
Print("Horde cleared!")```
**Line by line:**
- `@editable Spawner : creature_spawner_device = creature_spawner_device{}` — the field that lets you bind a placed Creature Spawner in the Details panel. Without this `@editable` field, calling its methods fails with `Unknown identifier`.
- `Spawner.SpawnedEvent.Subscribe(OnCreatureSpawned)` — `SpawnedEvent` is `listenable(agent)`, so its handler receives a plain `agent` (already unwrapped).
- `Spawner.EliminatedEvent.Subscribe(OnCreatureEliminated)` — `EliminatedEvent` is `listenable(device_ai_interaction_result)`. The result carries `Source` (the killer, a `?agent`) and `Target` (the creature that died).
- `StartPlate.TriggeredEvent.Subscribe(OnPlateStepped)` — `TriggeredEvent` is `listenable(?agent)`, so its handler takes a `?agent`.
- `Spawner.Disable()` in `OnBegin` keeps creatures from spawning until the plate is stepped.
- `Spawner.Enable()` turns the device on so its configured waves begin.
- `spawn { SpawnBonusWave() }` — `SpawnAt` is `<suspends>`, and our trigger handler is a non-suspending method, so we launch the async work with `spawn`.
- `Spawner.GetSpawnLimit()` returns the device's configured maximum spawn count (`<transacts>`, no side effect).
- `MaybeCreature := Spawner.SpawnAt(...)` then `if (Creature := MaybeCreature?)` — `SpawnAt` returns `?agent`; unwrap it because it's `false` if the device hit its cap.
- `Spawner.EliminateCreatures()` wipes all creatures this device spawned when the round is over.
## Common patterns
### Pattern 1 — Spawn a creature at a precise location with a rotation
Use the `?Rotation` named option when you want the creature to face a specific direction instead of the device's rotation.
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
using { /UnrealEngine.com/Temporary/Diagnostics }
spawn_at_marker := class(creative_device):
@editable
Spawner : creature_spawner_device = creature_spawner_device{}
# A prop marking where we want the creature to appear.
@editable
Marker : creative_prop = creative_prop{}
OnBegin<override>()<suspends>:void =
SpawnAtMarker()
SpawnAtMarker()<suspends>:void =
Where := Marker.GetGlobalTransform().Translation
Facing := IdentityRotation()
Maybe := Spawner.SpawnAt(Where, ?Rotation := Facing)
if (Creature := Maybe?):
Print("Creature spawned at the marker.")
else:
Print("Spawn failed — limit reached?")
Pattern 2 — Wipe the battlefield and shut down the spawner
A "safe room" panic button: clear every creature this spawner made, then permanently destroy the device.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
panic_button := class(creative_device):
@editable
Spawner : creature_spawner_device = creature_spawner_device{}
@editable
PanicButton : button_device = button_device{}
OnBegin<override>()<suspends>:void =
PanicButton.InteractedWithEvent.Subscribe(OnPanic)
OnPanic(Agent : agent):void =
# Remove all creatures this device spawned.
Spawner.EliminateCreatures()
# Then destroy the spawner so it never spawns again.
Spawner.DestroySpawner()
Print("Battlefield cleared and spawner destroyed.")
Pattern 3 — Score kills from EliminatedEvent
Give the player who eliminated a creature one point each, using the Source field of device_ai_interaction_result.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
kill_scoreboard := class(creative_device):
@editable
Spawner : creature_spawner_device = creature_spawner_device{}
@editable
ScoreManager : score_manager_device = score_manager_device{}
OnBegin<override>()<suspends>:void =
Spawner.Enable()
Spawner.EliminatedEvent.Subscribe(OnEliminated)
OnEliminated(Result : device_ai_interaction_result):void =
# Source is the killer; false if a non-agent (e.g. a trap) made the kill.
if (Killer := Result.Source?):
ScoreManager.Activate(Killer)
Print("Awarded a kill point.")
Gotchas
SpawnAtsuspends. It's<suspends>because the creature has to load. You can only call it from an async context — insideOnBegin, another<suspends>function, or viaspawn { ... }. Calling it directly from a non-suspending event handler won't compile.SpawnAtreturns?agent, notagent. It yieldsfalsewhen the device has reached its spawn cap, so always unwrap withif (Creature := Maybe?):before using the result.SpawnedEventvsEliminatedEventpayloads differ.SpawnedEventislistenable(agent)— its handler gets a ready-to-useagent.EliminatedEventislistenable(device_ai_interaction_result)— you read.Source(a?agent, the killer) and.Target(the creature). Don't write a handler expecting a bareagentforEliminatedEvent.Sourcecan befalse. If a non-agent eliminated the creature (a vehicle, fall, or trap),Result.Sourceisfalse. Always unwrap before scoring so you don't crash trying to use a missing killer.Disable()only stops the faucet; it doesn't remove existing creatures. If you want the field clear, callEliminateCreatures()as well.DestroySpawner()is permanent. After destroying the device, further calls (includingSpawnAt,Enable) target a device that no longer exists — design your flow so destruction is the last thing it does.- You must bind the device. The
@editablefield is required; a barecreature_spawner_device.SpawnAt(...)is anUnknown identifiererror. Drag your placed spawner onto the field in the Details panel.