Overview
The vehicle_spawner_tank_device is a specialized concrete subclass of vehicle_spawner_device that lets you place a configurable tank in your UEFN level and drive its entire lifecycle from Verse. Out of the box the device can spawn the tank automatically when the round starts, but the real power comes from Verse: you can disable the spawner so no tank appears until your script decides the moment is right, force-assign a specific player as driver, blow up the tank mid-match, and respawn a fresh one for the next wave — all while reacting to events that fire whenever an agent hops in or out, or whenever the vehicle is destroyed.
Reach for this device when you need:
- Scripted vehicle gates — only the round MVP gets to drive the tank.
- Wave resets — destroy and respawn the tank cleanly between combat waves.
- Stat tracking — count how many players entered the tank or how many times it was destroyed.
- Cinematic moments — assign a specific player as driver the instant a cutscene ends.
Because vehicle_spawner_tank_device inherits every method and event from vehicle_spawner_device, everything documented here applies equally to the base class pattern used by all other vehicle spawners.
API Reference
vehicle_spawner_tank_device
Specialized
vehicle_spawner_devicethat allows a tank to be configured and spawned.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from vehicle_spawner_device.
vehicle_spawner_tank_device<public> := class<concrete><final>(vehicle_spawner_device):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
AgentEntersVehicleEvent |
AgentEntersVehicleEvent<public>:listenable(agent) |
Signaled when an agent enters the vehicle. Sends the agent that entered the vehicle. |
AgentExitsVehicleEvent |
AgentExitsVehicleEvent<public>:listenable(agent) |
Signaled when an agent exits the vehicle. Sends the agent that exited the vehicle. |
SpawnedEvent |
SpawnedEvent<public>:listenable(fort_vehicle) |
Signaled when a vehicle is spawned or respawned by this device. Sends the fort_vehicle who was spawned. |
VehicleSpawnedEvent |
VehicleSpawnedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is spawned or respawned by this device. Deprecated, use SpawnedEvent instead. |
VehicleDestroyedEvent |
VehicleDestroyedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is destroyed. Deprecated, use DestroyedEvent instead. |
DestroyedEvent |
DestroyedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is destroyed. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
AssignDriver |
AssignDriver<public>(Agent:agent):void |
Sets agent as the vehicle's driver. |
DestroyVehicle |
DestroyVehicle<public>():void |
Destroys the vehicle if it exists. |
RespawnVehicle |
RespawnVehicle<public>():void |
Spawns a new vehicle. The previous vehicle will be destroyed before a new vehicle spawns. |
vehicle_spawner_device
Base class for various specialized vehicle spawners which allow specific vehicle types to be spawned and configured with specialized options.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
vehicle_spawner_device<public> := class<abstract><epic_internal>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
AgentEntersVehicleEvent |
AgentEntersVehicleEvent<public>:listenable(agent) |
Signaled when an agent enters the vehicle. Sends the agent that entered the vehicle. |
AgentExitsVehicleEvent |
AgentExitsVehicleEvent<public>:listenable(agent) |
Signaled when an agent exits the vehicle. Sends the agent that exited the vehicle. |
SpawnedEvent |
SpawnedEvent<public>:listenable(fort_vehicle) |
Signaled when a vehicle is spawned or respawned by this device. Sends the fort_vehicle who was spawned. |
VehicleSpawnedEvent |
VehicleSpawnedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is spawned or respawned by this device. Deprecated, use SpawnedEvent instead. |
VehicleDestroyedEvent |
VehicleDestroyedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is destroyed. Deprecated, use DestroyedEvent instead. |
DestroyedEvent |
DestroyedEvent<public>:listenable(tuple()) |
Signaled when a vehicle is destroyed. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
AssignDriver |
AssignDriver<public>(Agent:agent):void |
Sets agent as the vehicle's driver. |
DestroyVehicle |
DestroyVehicle<public>():void |
Destroys the vehicle if it exists. |
RespawnVehicle |
RespawnVehicle<public>():void |
Spawns a new vehicle. The previous vehicle will be destroyed before a new vehicle spawns. |
Walkthrough
Scenario: The Tank Gauntlet
A team-deathmatch map has one tank that only the round MVP (tracked by an external eliminations counter, simplified here to the first player who interacts with a button) may drive. When the round ends the tank is destroyed and respawned clean for the next round. A trigger_device acts as the "MVP button".
Here is the complete, compilable device:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Fortnite.com/Vehicles }
# Place this Verse device in your level, then wire up the
# @editable fields in the Details panel.
tank_gauntlet_manager := class(creative_device):
# The tank spawner placed in the level.
@editable TankSpawner : vehicle_spawner_tank_device = vehicle_spawner_tank_device{}
# A trigger_device the MVP steps on to claim the tank.
@editable MVPTrigger : trigger_device = trigger_device{}
# A button_device the game master presses to end the round.
@editable RoundEndButton : button_device = button_device{}
# Tracks whether a driver has already been assigned this round.
var DriverAssigned : logic = false
OnBegin<override>()<suspends> : void =
# Start with the tank disabled so it doesn't spawn until we're ready.
TankSpawner.Disable()
# Subscribe to all relevant events.
MVPTrigger.TriggeredEvent.Subscribe(OnMVPTriggered)
TankSpawner.AgentEntersVehicleEvent.Subscribe(OnAgentEnters)
TankSpawner.AgentExitsVehicleEvent.Subscribe(OnAgentExits)
TankSpawner.SpawnedEvent.Subscribe(OnTankSpawned)
TankSpawner.DestroyedEvent.Subscribe(OnTankDestroyed)
RoundEndButton.InteractedWithEvent.Subscribe(OnRoundEnd)
# Enable the spawner — the tank appears on the map.
TankSpawner.Enable()
# Called when the MVP steps on the trigger plate.
OnMVPTriggered(Agent : ?agent) : void =
# Unwrap the optional agent safely.
if (A := Agent?):
if (not DriverAssigned?):
set DriverAssigned = true
# Assign this player as the tank's driver immediately.
TankSpawner.AssignDriver(A)
# Called every time any agent boards the tank.
OnAgentEnters(Agent : agent) : void =
# AgentEntersVehicleEvent sends a plain agent, no unwrap needed.
Print("Agent entered the tank.")
# Called every time any agent leaves the tank.
OnAgentExits(Agent : agent) : void =
Print("Agent exited the tank.")
# SpawnedEvent sends the fort_vehicle that was spawned.
OnTankSpawned(Vehicle : fort_vehicle) : void =
Print("Tank spawned or respawned.")
set DriverAssigned = false
# DestroyedEvent sends tuple() — no payload.
OnTankDestroyed() : void =
Print("Tank destroyed.")
# Game master ends the round — destroy the tank then respawn it fresh.
OnRoundEnd(Agent : agent) : void =
TankSpawner.DestroyVehicle()
# RespawnVehicle destroys any existing vehicle and spawns a new one.
# We call it here so the next round starts with a clean tank.
TankSpawner.RespawnVehicle()```
### Line-by-line explanation
| Lines | What's happening |
|---|---|
| `@editable TankSpawner` | Declares the tank spawner as an editable field so you can wire it to the placed device in the Details panel. A bare `vehicle_spawner_tank_device{}` in a local variable would be an unconnected default — always use `@editable`. |
| `TankSpawner.Disable()` | Prevents the tank from auto-spawning while we finish setup. |
| `MVPTrigger.TriggeredEvent.Subscribe(OnMVPTriggered)` | `trigger_device.TriggeredEvent` fires with `?agent`, so the handler receives `Agent : ?agent`. |
| `TankSpawner.AgentEntersVehicleEvent.Subscribe(OnAgentEnters)` | This event fires with a plain `agent` (not optional), so the handler takes `Agent : agent` directly. |
| `TankSpawner.SpawnedEvent.Subscribe(OnTankSpawned)` | `SpawnedEvent` is `listenable(fort_vehicle)`, so the handler receives the spawned `fort_vehicle`. |
| `TankSpawner.DestroyedEvent.Subscribe(OnTankDestroyed)` | `DestroyedEvent` is `listenable(tuple())`, so the handler takes no parameters. |
| `TankSpawner.AssignDriver(A)` | Teleports the unwrapped agent into the driver's seat immediately. |
| `TankSpawner.DestroyVehicle()` | Blows up the current tank instance. |
| `TankSpawner.RespawnVehicle()` | Spawns a brand-new tank (destroying any existing one first). |
## Common patterns
### Pattern 1 — Disable the tank until a countdown finishes
Keep the tank locked away and only enable it after a timed delay, useful for battle-royale-style "tank drops in at 60 seconds".
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
tank_delayed_enable := class(creative_device):
@editable TankSpawner : vehicle_spawner_tank_device = vehicle_spawner_tank_device{}
# Seconds before the tank spawns.
@editable DelaySeconds : float = 60.0
OnBegin<override>()<suspends> : void =
# Tank is disabled in the device settings; we enable it after the delay.
TankSpawner.Disable()
Sleep(DelaySeconds)
TankSpawner.Enable()
# Enable() causes the spawner to spawn the tank immediately.
Pattern 2 — Auto-respawn the tank every time it is destroyed
For a king-of-the-hill mode where the tank must always be on the field.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
tank_always_present := class(creative_device):
@editable TankSpawner : vehicle_spawner_tank_device = vehicle_spawner_tank_device{}
OnBegin<override>()<suspends> : void =
TankSpawner.DestroyedEvent.Subscribe(OnTankDestroyed)
# DestroyedEvent payload is tuple() — handler takes no arguments.
OnTankDestroyed() : void =
# Brief pause so destruction VFX can finish, then respawn.
# We spawn a task so we can Sleep without blocking the event thread.
spawn { RespawnAfterDelay() }
RespawnAfterDelay()<suspends> : void =
Sleep(3.0)
TankSpawner.RespawnVehicle()
Pattern 3 — Track total time a player spends inside the tank
Use AgentEntersVehicleEvent and AgentExitsVehicleEvent together to measure ride duration.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
tank_ride_timer := class(creative_device):
@editable TankSpawner : vehicle_spawner_tank_device = vehicle_spawner_tank_device{}
# Wall-clock second when the current rider boarded.
var BoardTime : float = 0.0
# Accumulated ride seconds this session.
var TotalRideSeconds : float = 0.0
OnBegin<override>()<suspends> : void =
TankSpawner.AgentEntersVehicleEvent.Subscribe(OnEnter)
TankSpawner.AgentExitsVehicleEvent.Subscribe(OnExit)
# AgentEntersVehicleEvent sends a plain agent.
OnEnter(Agent : agent) : void =
set BoardTime = GetSimulationElapsedTime()
# AgentExitsVehicleEvent sends a plain agent.
OnExit(Agent : agent) : void =
ExitTime : float = GetSimulationElapsedTime()
RideDuration : float = ExitTime - BoardTime
set TotalRideSeconds = TotalRideSeconds + RideDuration
Print("Ride duration: {RideDuration}s | Total: {TotalRideSeconds}s")
Gotchas
1. Always use @editable — never construct the device inline
Writing TankSpawner : vehicle_spawner_tank_device = vehicle_spawner_tank_device{} without @editable creates a disconnected default object that has no connection to the placed device in your level. Every method call on it silently does nothing. Always declare the field with @editable and assign the placed device in the Details panel.
2. Event payload types differ — check before you write the handler
| Event | Payload type | Handler signature |
|---|---|---|
AgentEntersVehicleEvent |
agent (plain) |
OnEnter(Agent : agent) : void |
AgentExitsVehicleEvent |
agent (plain) |
OnExit(Agent : agent) : void |
SpawnedEvent |
fort_vehicle |
OnSpawned(Vehicle : fort_vehicle) : void |
DestroyedEvent |
tuple() |
OnDestroyed() : void |
VehicleSpawnedEvent (deprecated) |
tuple() |
OnVehicleSpawned() : void |
VehicleDestroyedEvent (deprecated) |
tuple() |
OnVehicleDestroyed() : void |
Mixing these up (e.g. writing OnSpawned(Agent : agent) for SpawnedEvent) is a compile error.
3. trigger_device.TriggeredEvent sends ?agent, not agent
When you chain a trigger to your tank logic, remember that TriggeredEvent fires with an optional agent. Unwrap it before passing to AssignDriver:
OnTriggered(Agent : ?agent) : void =
if (A := Agent?):
TankSpawner.AssignDriver(A)
Skipping the unwrap is a type error — AssignDriver expects a plain agent.
4. RespawnVehicle destroys the existing tank first
Calling RespawnVehicle() when a tank is already on the field will destroy it (firing DestroyedEvent) and then spawn a fresh one (firing SpawnedEvent). If your DestroyedEvent handler also calls RespawnVehicle(), you'll get an infinite loop. Guard with a flag or unsubscribe the handler before calling respawn.
5. Disable does not destroy the tank
Calling Disable() prevents the spawner from spawning new vehicles, but any tank already on the field stays alive. If you want to remove the tank entirely, call DestroyVehicle() first, then Disable().
6. Deprecated events — prefer the modern ones
VehicleSpawnedEvent and VehicleDestroyedEvent both send tuple() and are marked deprecated. Use SpawnedEvent (which gives you the fort_vehicle) and DestroyedEvent in all new code.