Overview
The effect_volume_device is the abstract base class for Fortnite's area-of-effect zone devices — the Damage Volume, Mutator Zone, and Skydive Volume. You place one in your map, configure what it does in the Details panel (deal damage, modify movement, force skydive, etc.), and then in Verse you control when it is active with two methods: Enable() and Disable().
Reach for it whenever a region of your map needs to change the rules of play: a lava pit that burns players, a low-gravity zone in a parkour challenge, a no-build bubble around the final circle, or a skydive launcher that only works during a mini-game phase.
The effect volume itself only knows how to switch on and off — it has no entry/exit events. To react to players crossing the boundary you pair it with a volume_device, a non-abstract tracker that fires AgentEntersEvent / AgentExitsEvent (and PropEnterEvent / PropExitEvent) and lets you query GetAgentsInVolume() or test IsInVolume(Agent). Place a volume_device over the same footprint as your effect volume and you get both the gameplay effect and the script hooks.
API Reference
effect_volume_device
Base class for types of volumes with special gameplay properties.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
effect_volume_device<public> := class<abstract><epic_internal>(creative_device_base):
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. |
volume_device
Used to track when agents enter and exit a volume.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
volume_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
AgentEntersEvent |
AgentEntersEvent<public>:listenable(agent) |
Signaled when an agent enters the device volume. |
AgentExitsEvent |
AgentExitsEvent<public>:listenable(agent) |
Signaled when an agent exits the device volume. |
PropEnterEvent |
PropEnterEvent<public>:listenable(creative_prop) |
Signaled when an creative_prop entered the device volume. |
PropExitEvent |
PropExitEvent<public>:listenable(creative_prop) |
Signaled when an creative_prop exited the device volume. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
GetAgentsInVolume |
GetAgentsInVolume<public>()<reads>:[]agent |
Returns an array of agents that are currently occupying the volume. |
IsInVolume |
IsInVolume<public>(Agent:agent)<transacts><decides>:void |
Succeeds when Agent is in the volume. |
Walkthrough
Scenario: A "floor is lava" arena. A Damage Volume (an effect_volume_device) sits over the lava pit and burns anyone inside, but only while the lava is active. A volume_device is placed over the same pit so we can announce who fell in and count survivors. The lava starts disabled, switches on after a warm-up, and we narrate entries/exits the whole time.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
# A 'floor is lava' controller built on the effect volume + a tracking volume.
lava_pit_game := class(creative_device):
# The Damage Volume placed over the lava pit. effect_volume_device gives us Enable/Disable.
@editable
LavaDamage : effect_volume_device = effect_volume_device{}
# A volume_device covering the SAME footprint, so we can detect entries/exits.
@editable
LavaTracker : volume_device = volume_device{}
OnBegin<override>()<suspends>:void =
# Lava is harmless during the warm-up: turn the damage effect off to start.
LavaDamage.Disable()
# React when players cross the boundary of the tracking volume.
LavaTracker.AgentEntersEvent.Subscribe(OnEnteredLava)
LavaTracker.AgentExitsEvent.Subscribe(OnLeftLava)
# Warm-up window, then the lava goes live.
Print("Get to high ground! Lava activates in 5 seconds...")
Sleep(5.0)
LavaDamage.Enable()
Print("The lava is HOT! Stay off the floor!")
# Anyone already standing in the pit when it heats up is in trouble.
BurningAgents := LavaTracker.GetAgentsInVolume()
Print("Players caught in the lava on activation: {BurningAgents.Length}")
# Handler for AgentEntersEvent — fires with the agent that crossed in.
OnEnteredLava(Agent : agent):void =
Print("An agent stepped into the lava pit!")
# Handler for AgentExitsEvent — fires with the agent that crossed out.
OnLeftLava(Agent : agent):void =
# IsInVolume<decides> lets us confirm state; here we just confirm they left.
if (not LavaTracker.IsInVolume[Agent]):
Print("An agent escaped the lava pit. Safe... for now.")
Line by line:
@editable LavaDamage : effect_volume_device— the field that binds to the Damage Volume you dropped in the level. You MUST declare devices as editable fields; calling a bareeffect_volume_device.Enable()would fail with Unknown identifier.@editable LavaTracker : volume_device— a second device over the same area.effect_volume_devicehas no entry events, so the tracker is what gives usAgentEntersEvent/AgentExitsEvent.LavaDamage.Disable()inOnBegin— start the round with the damage effect OFF so the warm-up is safe.LavaTracker.AgentEntersEvent.Subscribe(OnEnteredLava)— subscribe a class method as the handler. The event islistenable(agent), so the handler receives anagent.Sleep(5.0)—OnBeginis<suspends>, so we can await a real-time delay before enabling the effect.LavaDamage.Enable()— flips the volume on; from now on standing inside deals the damage configured in the Details panel.LavaTracker.GetAgentsInVolume()— returns[]agent; we read its.Lengthto count who got caught.OnLeftLavausesIsInVolume[Agent]— a<decides>query, called with square brackets, that succeeds when the agent is inside. We negate it withnot ...[]to confirm they're now out.
Common patterns
Toggle the effect from a player count threshold
Enable a Mutator Zone only once enough players have gathered inside it, using GetAgentsInVolume() to count.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
arena_gate := class(creative_device):
@editable
MutatorEffect : effect_volume_device = effect_volume_device{}
@editable
Tracker : volume_device = volume_device{}
OnBegin<override>()<suspends>:void =
MutatorEffect.Disable()
Tracker.AgentEntersEvent.Subscribe(OnAgentEntered)
OnAgentEntered(Agent : agent):void =
Count := Tracker.GetAgentsInVolume().Length
Print("Players in the staging zone: {Count}")
if (Count >= 3):
# Enough players gathered — turn on the zone's gameplay effect.
MutatorEffect.Enable()
Print("Mutator zone ACTIVE — the rules have changed!")
React to a thrown prop entering the zone
A volume_device also tracks props. Disable a Damage Volume when a special prop is tossed in (e.g. an extinguisher prop dropped into the fire).
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
fire_zone := class(creative_device):
@editable
FireDamage : effect_volume_device = effect_volume_device{}
@editable
Tracker : volume_device = volume_device{}
OnBegin<override>()<suspends>:void =
FireDamage.Enable()
Tracker.PropEnterEvent.Subscribe(OnPropEntered)
Tracker.PropExitEvent.Subscribe(OnPropExited)
OnPropEntered(Prop : creative_prop):void =
# Extinguisher prop landed in the fire — put it out.
FireDamage.Disable()
Print("A prop landed in the fire zone — damage disabled.")
OnPropExited(Prop : creative_prop):void =
# Prop removed — relight the fire.
FireDamage.Enable()
Print("Prop left the zone — fire reignited.")
Check membership on demand with IsInVolume
Use IsInVolume[Agent] from any other logic — here a periodic safety check that re-enables a Skydive Volume if it ever empties.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
skydive_loop := class(creative_device):
@editable
SkydiveEffect : effect_volume_device = effect_volume_device{}
@editable
Tracker : volume_device = volume_device{}
@editable
TestPlayerSpawn : player_spawner_device = player_spawner_device{}
OnBegin<override>()<suspends>:void =
SkydiveEffect.Enable()
loop:
Sleep(2.0)
Agents := Tracker.GetAgentsInVolume()
for (A : Agents):
# IsInVolume<decides> — square brackets, succeeds when inside.
if (Tracker.IsInVolume[A]):
Print("An agent is still in the skydive volume.")
Gotchas
- The effect volume has NO entry/exit events.
effect_volume_deviceonly exposesEnable()andDisable(). If you need to know who entered, place a separatevolume_deviceover the same area and subscribe to itsAgentEntersEvent/AgentExitsEvent. effect_volume_deviceis abstract. You never place a literal "effect volume" — you place a concrete child (Damage Volume, Mutator Zone, Skydive Volume) and bind it to aneffect_volume_device-typed@editablefield. What the volume actually does is configured in the Details panel, not in Verse.IsInVolumeis<decides>, call it with square brackets. Writeif (Tracker.IsInVolume[Agent]):, not(...). Using parentheses or treating it like a bool returns a compile error. To test the negative, wrap it:if (not Tracker.IsInVolume[Agent]):.listenable(agent)handlers already receive anagent. The signature here hands you a plainagent(not?agent), so noAgent?unwrap is needed — but if you store it and later need theplayer, you still must validate withif (Player := Agent.GetFortCharacter[]...)style queries.- Enable/Disable do not move players. Disabling a Damage Volume stops new damage ticks but doesn't heal anyone; enabling a Skydive Volume only affects agents currently inside or who enter afterward. Combine with
GetAgentsInVolume()if you need to act on whoever is caught at the moment of the toggle. Sleep/loops require<suspends>. The warm-up and polling examples only work insideOnBegin<override>()<suspends>. You cannotSleepinside a plain event handler method.