Overview
The vehicle_spawner_surfboard_device is a concrete, final specialization of the abstract vehicle_spawner_device base class. Drop one into your level from the Content Browser and it will spawn a surfboard at its location when the game starts (if configured to do so). From Verse you can:
- Enable / Disable the spawner so the board only appears during the right phase of your game.
- RespawnVehicle to reset the board to its spawn point mid-match (great for a surf-race reset mechanic).
- DestroyVehicle to blow the board up on a timer or as a punishment.
- AssignDriver to force a specific player onto the board automatically.
- React to AgentEntersVehicleEvent, AgentExitsVehicleEvent, SpawnedEvent, and DestroyedEvent to drive score, UI, or other game logic.
Reach for this device whenever your island needs a player-rideable surfboard that your Verse code must orchestrate — timed challenges, race gates, VIP transports, or wave-surfing arenas.
API Reference
vehicle_spawner_surfboard_device
Specialized
vehicle_spawner_devicethat allows a surfboard 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_surfboard_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: Surf-Race Checkpoint Arena
A player steps on a trigger_device to start the race. The surfboard spawns (or respawns if it was already out), the player is automatically assigned as driver, a 60-second countdown begins, and when time runs out the board is destroyed. If the player bails early (exits the vehicle), the board is immediately respawned so the next racer can go.
Place in your level:
- One
vehicle_spawner_surfboard_device(name itSurfSpawnerin the Outliner) - One
trigger_device(name itStartTrigger)
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Fortnite.com/Vehicles }
surf_race_manager := class(creative_device):
# Wire these up in the Details panel
@editable
SurfSpawner : vehicle_spawner_surfboard_device = vehicle_spawner_surfboard_device{}
@editable
StartTrigger : trigger_device = trigger_device{}
# Track whether a race is in progress so we don't double-start
var RaceActive : logic = false
OnBegin<override>()<suspends> : void =
# Subscribe to the start trigger
StartTrigger.TriggeredEvent.Subscribe(OnRaceStart)
# React when a player bails off the board
SurfSpawner.AgentExitsVehicleEvent.Subscribe(OnSurferExited)
# React when the board is destroyed (timer expired)
SurfSpawner.DestroyedEvent.Subscribe(OnBoardDestroyed)
# React when a fresh board finishes spawning
SurfSpawner.SpawnedEvent.Subscribe(OnBoardSpawned)
# Start disabled — only enable when a race begins
SurfSpawner.Disable()
# Called when the trigger fires (agent is ?agent so we unwrap it)
OnRaceStart(Agent : ?agent) : void =
if (set RaceActive = false, A := Agent?):
set RaceActive = true
# Enable the spawner and get a fresh board
SurfSpawner.Enable()
SurfSpawner.RespawnVehicle()
# Assign the triggering player as driver
SurfSpawner.AssignDriver(A)
# Start the countdown on a separate async task
spawn { RunCountdown() }
# Fires when SpawnedEvent signals — receives the fort_vehicle
OnBoardSpawned(Vehicle : fort_vehicle) : void =
# You could store Vehicle here or display a UI message
# For now we just note the board is live
if (RaceActive?):
# Board is ready — race is already running
# If the surfer bails, respawn the board for the next player
OnSurferExited(Agent : agent) : void =
if (RaceActive?):
set RaceActive = false
SurfSpawner.RespawnVehicle()
# When the board is destroyed, lock the spawner until next race
OnBoardDestroyed(Empty : tuple()) : void =
set RaceActive = false
SurfSpawner.Disable()
# 60-second race timer — destroys the board when it expires
RunCountdown()<suspends> : void =
Sleep(60.0)
if (RaceActive?):
SurfSpawner.DestroyVehicle()```
**Line-by-line highlights:**
| Lines | What's happening |
|---|---|
| `@editable SurfSpawner` | Declares the device field — without this, `SurfSpawner.Enable()` would fail with *Unknown identifier*. |
| `StartTrigger.TriggeredEvent.Subscribe(OnRaceStart)` | Hooks the trigger. The handler receives `?agent` — we unwrap with `if (A := Agent?)`. |
| `SurfSpawner.Disable()` | Hides the board at game start; only re-enabled when a race begins. |
| `SurfSpawner.RespawnVehicle()` | Destroys any existing board and spawns a fresh one at the spawner's location. |
| `SurfSpawner.AssignDriver(A)` | Puts the player on the board automatically — no manual boarding needed. |
| `SurfSpawner.SpawnedEvent.Subscribe(OnBoardSpawned)` | Uses the **non-deprecated** event that sends the actual `fort_vehicle`. |
| `SurfSpawner.DestroyedEvent.Subscribe(OnBoardDestroyed)` | Uses the **non-deprecated** replacement for `VehicleDestroyedEvent`. |
| `spawn { RunCountdown() }` | Runs the 60-second timer concurrently without blocking `OnBegin`. |
| `SurfSpawner.DestroyVehicle()` | Ends the race by destroying the board; triggers `DestroyedEvent`. |
---
## Common patterns
### Pattern 1 — Toggle the spawner with a button (Enable / Disable)
A button in the lobby activates the surfboard zone. A second button deactivates it and destroys any live board.
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
surf_toggle_device := class(creative_device):
@editable
SurfSpawner : vehicle_spawner_surfboard_device = vehicle_spawner_surfboard_device{}
@editable
ActivateButton : button_device = button_device{}
@editable
DeactivateButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
SurfSpawner.Disable() # Off by default
ActivateButton.InteractedWithEvent.Subscribe(OnActivate)
DeactivateButton.InteractedWithEvent.Subscribe(OnDeactivate)
OnActivate(Agent : agent) : void =
SurfSpawner.Enable()
SurfSpawner.RespawnVehicle()
OnDeactivate(Agent : agent) : void =
SurfSpawner.DestroyVehicle() # Remove the board first
SurfSpawner.Disable() # Then lock the spawner
Pattern 2 — Auto-assign driver when a player enters a zone (AssignDriver + AgentEntersVehicleEvent)
When a player walks into a trigger zone near the board, they are automatically assigned as driver. When they exit the vehicle, the board respawns for the next player.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
surf_autoboard_device := class(creative_device):
@editable
SurfSpawner : vehicle_spawner_surfboard_device = vehicle_spawner_surfboard_device{}
@editable
BoardingZone : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
BoardingZone.TriggeredEvent.Subscribe(OnPlayerEntersZone)
SurfSpawner.AgentEntersVehicleEvent.Subscribe(OnMounted)
SurfSpawner.AgentExitsVehicleEvent.Subscribe(OnDismounted)
# Trigger sends ?agent — unwrap before use
OnPlayerEntersZone(Agent : ?agent) : void =
if (A := Agent?):
SurfSpawner.AssignDriver(A)
OnMounted(Agent : agent) : void =
# Player is now riding — could start a score timer here
OnDismounted(Agent : agent) : void =
# Board is free — respawn it so the next player can ride
SurfSpawner.RespawnVehicle()
Pattern 3 — Periodic board reset (RespawnVehicle on a loop)
In a free-roam surf park, the board resets to its spawn point every 45 seconds so it never drifts too far from the start.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
surf_reset_loop_device := class(creative_device):
@editable
SurfSpawner : vehicle_spawner_surfboard_device = vehicle_spawner_surfboard_device{}
# How often (seconds) the board resets
ResetInterval : float = 45.0
OnBegin<override>()<suspends> : void =
SurfSpawner.Enable()
SurfSpawner.SpawnedEvent.Subscribe(OnBoardSpawned)
loop:
Sleep(ResetInterval)
SurfSpawner.RespawnVehicle() # Destroys old board, spawns fresh one
OnBoardSpawned(Vehicle : fort_vehicle) : void =
# The fresh fort_vehicle reference is available here if needed
Gotchas
1. Always declare the device as an @editable field
You cannot write vehicle_spawner_surfboard_device{}.Enable() inline. The device must be an @editable field wired in the Details panel. A bare local variable has no connection to the placed actor and every method call silently does nothing (or fails to compile).
# ✅ Correct
@editable
SurfSpawner : vehicle_spawner_surfboard_device = vehicle_spawner_surfboard_device{}
# ❌ Wrong — not wired to anything in the level
LocalBoard := vehicle_spawner_surfboard_device{}
LocalBoard.Enable() # This device is not the one in your scene
2. Use SpawnedEvent and DestroyedEvent, not the deprecated ones
VehicleSpawnedEvent and VehicleDestroyedEvent are deprecated as of 25.00. Use SpawnedEvent (which sends the fort_vehicle) and DestroyedEvent instead. The deprecated events send an empty tuple() and will be removed in a future release.
3. AgentEntersVehicleEvent sends agent, but trigger_device.TriggeredEvent sends ?agent
These are different types. AgentEntersVehicleEvent and AgentExitsVehicleEvent send a non-optional agent directly — no unwrapping needed. trigger_device.TriggeredEvent sends ?agent — always unwrap with if (A := Agent?): before calling any agent API.
# AgentEntersVehicleEvent — agent is NOT optional
OnMounted(Agent : agent) : void =
# Use Agent directly
# trigger_device.TriggeredEvent — agent IS optional
OnTriggered(Agent : ?agent) : void =
if (A := Agent?):
SurfSpawner.AssignDriver(A)
4. RespawnVehicle destroys the existing board first
Calling RespawnVehicle() when a board is already live will destroy it and then spawn a fresh one. This triggers DestroyedEvent. If your DestroyedEvent handler calls RespawnVehicle() again you will create an infinite loop. Guard with a flag (var RaceActive : logic) as shown in the Walkthrough.
5. AssignDriver requires the vehicle to exist
If you call AssignDriver before the board has finished spawning, the call may have no effect. Subscribe to SpawnedEvent and call AssignDriver from inside that handler (or after RespawnVehicle has had time to complete) to be safe. Alternatively, call it immediately after RespawnVehicle — the engine queues the assignment for when the vehicle is ready.
6. No message parameters on this device
vehicle_spawner_surfboard_device has no text-display methods, so you won't hit the message vs string pitfall here. But if you pair it with a hud_message_device to show race text, remember: message parameters require a <localizes> function — there is no StringToMessage helper.
# Correct way to pass dynamic text to a message param elsewhere
RaceText<localizes>(S : string) : message = "{S}"