Overview
The spire_spike_device represents a classic Spire Spike prop from Fortnite's Spire POI. It solves three game-design problems at once:
- Hazard prop — it damages and knocks back players who stand too close, without dealing fall damage, making it a safe-but-dramatic environmental threat.
- Loot piñata — destroying it drops configurable loot, so it becomes a risk/reward objective.
- Scriptable state machine — via Verse you can spawn, despawn, force-destroy, and trigger the knockback on demand, letting you build wave-based arenas, puzzle rooms, or timed challenges around it.
Reach for spire_spike_device when you want a prop that actively fights back and whose lifecycle (spawn → charge → knockback → destroy → respawn) you need to control from code.
API Reference
spire_spike_device
A Destroyable environment prop that when destroyed, drops loot. When players approach the Spire Spike, they start a countdown to a knockback ability. When players are knocked back, they do not receive damage from the knockback ability or take fall damage. They can destroy structures near the knockback location. Damaging the spike can also start the countdown to the knockback or restart the countdo
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
spire_spike_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
KnockbackEvent |
KnockbackEvent<public>:listenable(tuple()) |
Triggers when the Spire Spike does its knockback ability. |
DestroyEvent |
DestroyEvent<public>:listenable(?agent) |
Triggers when the Spire Spike is destroyed. Includes the agent that destroyed it, if any. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Destroy |
Destroy<public>(Instigator:?agent):void |
Destroy the Spire Spike. Will cause the Spire Spike to drop its loot. |
Spawn |
Spawn<public>():void |
Spawn the Spire Spike. Resets CurrentHealth back to max health. Resets any timers currently active. |
Despawn |
Despawn<public>():void |
Despawns the Spire Spike. It will not drop loot. |
IsSpawned |
IsSpawned<public>()<transacts><decides>:void |
Returns if Spire Spike is currently spawned. |
Knockback |
Knockback<public>():void |
Force the Spire Spike to trigger its knockback ability immediately. |
ChargeKnockback |
ChargeKnockback<public>():void |
Force begins the knockback charge timer. Will restart the charge timer if already active. |
Walkthrough
Scenario: "Defend the Spike" Arena Round
A round-based arena where:
- The Spike spawns at round start.
- Any player who gets too close triggers the knockback — the Verse device logs it and starts a charge timer for the next knockback.
- When the Spike is finally destroyed, the killer is announced and the Spike respawns after a short delay for the next round.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
# Helper to convert a string into a localizable message
SpikeMsg<localizes>(S : string) : message = "{S}"
defend_the_spike_manager := class(creative_device):
# Wire this to your placed spire_spike_device in the UEFN Outliner
@editable
Spike : spire_spike_device = spire_spike_device{}
# Wire this to a HUD Message device so players see announcements
@editable
HUD : hud_message_device = hud_message_device{}
# Seconds to wait before respawning the Spike after destruction
@editable
RespawnDelay : float = 5.0
OnBegin<override>()<suspends> : void =
# Subscribe to both events at startup
Spike.KnockbackEvent.Subscribe(OnKnockback)
Spike.DestroyEvent.Subscribe(OnSpikeDestroyed)
# Make sure the Spike is alive and fully reset at round start
Spike.Spawn()
# Immediately begin charging the knockback timer so the
# first player to approach gets launched quickly
Spike.ChargeKnockback()
# Called every time the Spike fires its knockback ability
# KnockbackEvent is listenable(tuple()) — handler takes no payload
OnKnockback() : void =
HUD.SetText(SpikeMsg("⚡ Spike launched someone! Charge restarting…"))
HUD.Show()
# Restart the charge so the next victim is launched sooner
Spike.ChargeKnockback()
# Called when the Spike is destroyed
# DestroyEvent is listenable(?agent) — payload is an optional agent
OnSpikeDestroyed(Destroyer : ?agent) : void =
if (A := Destroyer?):
# A real player destroyed it — celebrate them
HUD.SetText(SpikeMsg("💥 Spike destroyed! Respawning soon…"))
else:
HUD.SetText(SpikeMsg("💥 Spike fell on its own! Respawning…"))
HUD.Show()
# Wait, then bring the Spike back for the next round
spawn { RespawnAfterDelay() }
RespawnAfterDelay()<suspends> : void =
Sleep(RespawnDelay)
# Spawn() resets health AND cancels any active timers
Spike.Spawn()
# Kick off the charge immediately for the fresh Spike
Spike.ChargeKnockback()
HUD.SetText(SpikeMsg("🌀 Spike is back — stay away!"))
HUD.Show()
Line-by-line breakdown
| Lines | What's happening |
|---|---|
@editable Spike |
Declares the device reference so UEFN can wire it in the Outliner. Without @editable the identifier is unknown at runtime. |
Spike.KnockbackEvent.Subscribe(OnKnockback) |
Registers OnKnockback to fire every time the Spike launches players. |
Spike.DestroyEvent.Subscribe(OnSpikeDestroyed) |
Registers OnSpikeDestroyed; the payload is ?agent (optional). |
Spike.Spawn() |
Resets health to max and cancels any active timers — safe to call even if already spawned. |
Spike.ChargeKnockback() |
Starts (or restarts) the internal countdown. When it completes the Spike fires its knockback. |
if (A := Destroyer?) |
Unwraps the ?agent option — required before you can use the agent value. |
spawn { RespawnAfterDelay() } |
Runs the async respawn coroutine without blocking the event handler. |
Common patterns
Pattern 1 — Instant knockback trap (pressure-plate trigger)
A player steps on a trigger plate hidden under the Spike; the Spike immediately fires its knockback without waiting for the charge timer.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
instant_knockback_trap := class(creative_device):
@editable
Spike : spire_spike_device = spire_spike_device{}
# A trigger_device placed under the Spike in the level
@editable
Plate : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
Spike.Spawn()
# Subscribe to the trigger plate
Plate.TriggeredEvent.Subscribe(OnPlateTriggered)
# trigger_device.TriggeredEvent is listenable(?agent)
OnPlateTriggered(Agent : ?agent) : void =
# Bypass the charge timer — launch anyone nearby RIGHT NOW
Spike.Knockback()
Key call: Spike.Knockback() fires the knockback ability immediately, skipping the charge countdown entirely. Use this for scripted moments — a boss ability, a puzzle punishment, a timed trap.
Pattern 2 — Conditional despawn (safe zone cleanup)
When a game phase ends, silently despawn the Spike (no loot drop) so the arena is clear for the next phase. If a new phase starts, spawn a fresh one.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
phase_spike_controller := class(creative_device):
@editable
Spike : spire_spike_device = spire_spike_device{}
# Two buttons wired in the Outliner: one ends the phase, one starts it
@editable
EndPhaseButton : button_device = button_device{}
@editable
StartPhaseButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
EndPhaseButton.InteractedWithEvent.Subscribe(OnEndPhase)
StartPhaseButton.InteractedWithEvent.Subscribe(OnStartPhase)
Spike.Spawn()
OnEndPhase(Agent : ?agent) : void =
# Check it is actually spawned before despawning
if (Spike.IsSpawned[]):
# Despawn silently — NO loot drop
Spike.Despawn()
OnStartPhase(Agent : ?agent) : void =
# Spawn() is safe to call whether despawned or already alive
Spike.Spawn()
Spike.ChargeKnockback()
Key calls: IsSpawned[] (failable — use inside if) guards against calling Despawn() on an already-gone Spike. Despawn() removes it with no loot, while Destroy() removes it with loot.
Pattern 3 — Scripted destruction reward (boss kill)
A game manager destroys the Spike programmatically (with loot) when the boss health reaches zero, crediting the killing player.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }
SpikeRewardMsg<localizes>(S : string) : message = "{S}"
boss_spike_reward := class(creative_device):
@editable
Spike : spire_spike_device = spire_spike_device{}
@editable
HUD : hud_message_device = hud_message_device{}
# Called externally (e.g. from a damage volume event) with the killing agent
# Exposed as a public method so other devices can call it
AwardSpikeDestruction(Killer : agent) : void =
if (Spike.IsSpawned[]):
# Destroy WITH loot drop, crediting the killer agent
Spike.Destroy(option{Killer})
HUD.SetText(SpikeRewardMsg("🏆 Boss Spike destroyed — loot incoming!"))
HUD.Show()
OnBegin<override>()<suspends> : void =
Spike.Spawn()
# Listen for the destroy event to confirm it fired
Spike.DestroyEvent.Subscribe(OnConfirmDestroy)
OnConfirmDestroy(Destroyer : ?agent) : void =
HUD.SetText(SpikeRewardMsg("✅ Spike destruction confirmed."))
HUD.Show()
Key call: Spike.Destroy(option{Killer}) passes the agent wrapped in option{} to match the ?agent parameter type. The Spike drops its loot and fires DestroyEvent.
Gotchas
1. IsSpawned[] is failable — always use it inside if
IsSpawned has the <decides> effect, meaning it can fail (return false). You must call it inside an if expression:
# ✅ Correct
if (Spike.IsSpawned[]):
Spike.Despawn()
# ❌ Wrong — compile error, <decides> outside if
Spike.IsSpawned()
2. KnockbackEvent handler takes no arguments
KnockbackEvent is listenable(tuple()) — its payload is an empty tuple. Your handler must match the signature () : void, not (Agent : ?agent) : void:
# ✅ Correct
OnKnockback() : void = ...
# ❌ Wrong — mismatched handler signature
OnKnockback(A : ?agent) : void = ...
3. DestroyEvent payload is ?agent, not agent
The destroyer may be the environment (no agent). Always unwrap with if (A := Destroyer?) before using the agent. Skipping this causes a type error.
4. Destroy() vs Despawn() — loot matters
Destroy(Instigator : ?agent)→ Spike health → 0, drops loot, firesDestroyEvent.Despawn()→ Spike vanishes silently, no loot, no event.
Using Despawn() when you intended Destroy() will confuse players who expect a loot reward.
5. ChargeKnockback() restarts the timer
Calling ChargeKnockback() while a charge is already running resets the countdown to zero. If you call it in a tight loop you will prevent the Spike from ever firing. Only call it after a knockback has resolved or after Spawn().
6. Localized text for hud_message_device.SetText
SetText takes a message, not a raw string. Declare a helper:
MyMsg<localizes>(S : string) : message = "{S}"
Then pass MyMsg("your text"). There is no StringToMessage function in Verse.