Overview
The physics_object_base_device is the abstract base class behind UEFN's physics-driven prop spawners — things like the Physics Boulder and physics-tree props. You never place a physics_object_base_device directly; instead you place one of its concrete children (for example physics_boulder_device), but every one of them inherits the same core control surface defined here.
That shared surface solves a very common game problem: I want a heavy physics object to appear, do its physics thing, and then be cleaned up — all under script control. Picture an obstacle course where stepping on a pressure plate drops a boulder, or a defense round where you spawn a wave of destructible trees and then wipe them all when the round ends.
Reach for this device's API when you want to:
- Spawn the physics prop on demand with
SpawnObject(). - Turn the spawner on/off with
Enable()/Disable()so it can't fire while disabled. - Clean up every prop it created in one shot with
DestroyAllSpawnedObjects().
Because it descends from prop_spawner_base_device, the concrete devices (like the boulder) also add their own events on top — but the four methods below are the reliable, always-available foundation.
API Reference
physics_object_base_device
Base class for various physics-based gameplay elements (e.g. boulders/trees).
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from prop_spawner_base_device.
physics_object_base_device<public> := class<abstract><epic_internal>(prop_spawner_base_device):
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. |
SpawnObject |
SpawnObject<public>():void |
Spawns the prop associated with this device. |
DestroyAllSpawnedObjects |
DestroyAllSpawnedObjects<public>():void |
Destroys all props spawned from this device. |
Walkthrough
Let's build a classic boulder trap. A player steps on a trigger_device; we spawn a boulder from a physics_boulder_device (a concrete physics_object_base_device). When the round-end button_device is pressed, we destroy every boulder we spawned and disable the spawner so no more can drop.
We declare each placed device as an @editable field so Verse can actually reach it, then wire the events in OnBegin.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# A boulder-trap manager. Drag the matching devices onto these slots in UEFN.
boulder_trap_device := class(creative_device):
# The physics boulder spawner. physics_boulder_device IS a physics_object_base_device.
@editable
BoulderSpawner : physics_boulder_device = physics_boulder_device{}
# Player steps here to drop a boulder.
@editable
TrapTrigger : trigger_device = trigger_device{}
# Pressed at round end to clean everything up.
@editable
ResetButton : button_device = button_device{}
OnBegin<override>()<suspends>:void =
# Make sure the spawner is active when the round starts.
BoulderSpawner.Enable()
# Wire the trigger and the reset button to our handler methods.
TrapTrigger.TriggeredEvent.Subscribe(OnTrapStepped)
ResetButton.InteractedWithEvent.Subscribe(OnResetPressed)
# Runs each time a player steps on the trap trigger.
OnTrapStepped(Agent : ?agent):void =
# Drop a fresh boulder from the spawner.
BoulderSpawner.SpawnObject()
# Runs when a player interacts with the reset button.
OnResetPressed(Agent : agent):void =
# Wipe every boulder this spawner created...
BoulderSpawner.DestroyAllSpawnedObjects()
# ...and stop it from spawning any more until we re-enable it.
BoulderSpawner.Disable()
Line by line:
@editable BoulderSpawner : physics_boulder_device— the concrete boulder spawner. Because it inherits fromphysics_object_base_device, calling.Enable(),.SpawnObject(), and.DestroyAllSpawnedObjects()on it is valid. A barephysics_object_base_devicefield would be illegal — it's<abstract>and can't be instantiated or placed.OnBegin<override>()<suspends>:void— the device's entry point. We callBoulderSpawner.Enable()first so the spawner is guaranteed live.TrapTrigger.TriggeredEvent.Subscribe(OnTrapStepped)— subscribes our method to the trigger's event. The trigger'sTriggeredEventislistenable(?agent), so the handler takes(Agent : ?agent).OnTrapStepped— every time someone steps on the plate,SpawnObject()makes a new boulder appear and roll/fall with real physics.OnResetPressed—DestroyAllSpawnedObjects()removes the whole pile of boulders, thenDisable()shuts the spawner off so the trap is safe until youEnable()it again.
Common patterns
1. Spawn a wave on a timer, then clear it
Use a timer_device so a boulder drops every time the timer completes, and a separate signal to flush them all.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
wave_spawner_device := class(creative_device):
@editable
Spawner : physics_boulder_device = physics_boulder_device{}
@editable
WaveTimer : timer_device = timer_device{}
@editable
ClearButton : button_device = button_device{}
OnBegin<override>()<suspends>:void =
Spawner.Enable()
# Each time the timer finishes, spawn another physics object.
WaveTimer.SuccessEvent.Subscribe(OnTimerDone)
ClearButton.InteractedWithEvent.Subscribe(OnClear)
WaveTimer.Start()
OnTimerDone(Agent : ?agent):void =
Spawner.SpawnObject()
OnClear(Agent : agent):void =
Spawner.DestroyAllSpawnedObjects()
2. Gate spawning behind game state with Enable / Disable
Keep the spawner disabled until a round actually starts, so stray triggers can't pre-fire it.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
round_gate_device := class(creative_device):
@editable
Spawner : physics_boulder_device = physics_boulder_device{}
@editable
StartButton : button_device = button_device{}
@editable
EndButton : button_device = button_device{}
OnBegin<override>()<suspends>:void =
# Start the round with the spawner OFF.
Spawner.Disable()
StartButton.InteractedWithEvent.Subscribe(OnRoundStart)
EndButton.InteractedWithEvent.Subscribe(OnRoundEnd)
OnRoundStart(Agent : agent):void =
Spawner.Enable()
Spawner.SpawnObject()
OnRoundEnd(Agent : agent):void =
Spawner.Disable()
Spawner.DestroyAllSpawnedObjects()
3. Burst-spawn several objects at once
SpawnObject() spawns one prop per call — loop it for a burst, then offer a one-call cleanup.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
burst_spawner_device := class(creative_device):
@editable
Spawner : physics_boulder_device = physics_boulder_device{}
@editable
BurstTrigger : trigger_device = trigger_device{}
@editable
Count : int = 5
OnBegin<override>()<suspends>:void =
Spawner.Enable()
BurstTrigger.TriggeredEvent.Subscribe(OnBurst)
OnBurst(Agent : ?agent):void =
# Drop `Count` physics objects in a single burst.
for (I := 0..Count - 1):
Spawner.SpawnObject()
Gotchas
- The base class is abstract — you place a child.
physics_object_base_deviceis<abstract>, so you cannot place it or writephysics_object_base_device{}. Declare your@editablefield as a concrete subclass such asphysics_boulder_deviceand drop that device in UEFN; it inherits all four methods. - No events live on the base class. The base surface is methods only —
Enable,Disable,SpawnObject,DestroyAllSpawnedObjects. Events likeBalancedBoulderSpawnedEventbelong to the concretephysics_boulder_device, not tophysics_object_base_device. Don't try toSubscribeto an event on the base type. SpawnObject()does nothing while disabled. If you've calledDisable()(or never enabled the device), spawns may not occur. AlwaysEnable()before you expect spawns, and rememberDestroyAllSpawnedObjects()only removes props this device spawned.- Reach the device through an
@editablefield. A barephysics_boulder_device{}.SpawnObject()won't work — you need a field referencing the placed device. Calling a method on a default-constructedphysics_boulder_device{}with no real placement behind it does nothing in the world. - Unwrap
?agentfrom trigger events. Atrigger_device.TriggeredEventhandler receives(Agent : ?agent). If you need the actual player, unwrap withif (A := Agent?):before using it; buttonInteractedWithEventinstead hands you a plainagent. DestroyAllSpawnedObjects()is a clean-up, not a disable. It removes existing props but the spawner stays enabled and will happily spawn again — pair it withDisable()if you want spawning to actually stop.