Overview
The capture_area_device defines a cylindrical volume on your island. At its simplest it fires AgentEntersEvent / AgentExitsEvent so you can use it as a fancy trigger zone — great for automatic doors, proximity traps, or safe-zone enforcement. Turn on Capture mode in the Details panel and it becomes a full control point: teams contest it, a progress bar fills, control changes hands, and AreaIsScoredEvent fires on every periodic tick while a team holds it.
Reach for it when you need:
- A domination / king-of-the-hill control point
- A flag delivery zone (pair with
capture_item_spawner_device) - A proximity trigger that knows how many players are inside (
GetAgentsInVolume) - A zone you can resize at runtime (
SetRadius,SetHeight) or lock/unlock mid-game (DisallowCapture/AllowCapture) - An objective pulse that draws players to the zone (
ActivateObjectivePulse)
API Reference
capture_area_device
Used to create a zone that can trigger effects once players enter it. Can be set up to be capturable by a team, to provide a score while held, or to require a specific item as a drop-off.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
capture_area_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 this device area. Sends the agent that entered this device area. |
AgentExitsEvent |
AgentExitsEvent<public>:listenable(agent) |
Signaled when an agent exits this device area. Sends the agent that exited this device area. |
FirstAgentEntersEvent |
FirstAgentEntersEvent<public>:listenable(agent) |
Signaled when the first agent enters this device area. Sends the agent that entered this device area. |
LastAgentExitsEvent |
LastAgentExitsEvent<public>:listenable(agent) |
Signaled when the last agent exits this device area. Sends the agent that exited this device area. |
AreaIsContestedEvent |
AreaIsContestedEvent<public>:listenable(agent) |
Signaled when this device is contested. Sends the agent that is contesting this device. |
AreaIsScoredEvent |
AreaIsScoredEvent<public>:listenable(agent) |
Signaled when this device is scored. Sends the agent that scored this device. |
ControlChangeStartsEvent |
ControlChangeStartsEvent<public>:listenable(agent) |
Signaled when this device control change starts. Sends the agent that is triggering this device control change. |
ControlChangeEvent |
ControlChangeEvent<public>:listenable(agent) |
Signaled when this device control changes. Sends the agent that triggered this device control change. |
NeutralizeEvent |
NeutralizeEvent<public>:listenable(?agent) |
Signaled when this device enters the neutralized state. Sends the agent that was responsible for neutralizing the area (the player in the area at the time of neutralization, prioritized by the one who has been in the area the longest), if |
ItemIsConsumedEvent |
ItemIsConsumedEvent<public>:listenable(agent) |
Signaled when an item is consumed by this device. Sends the agent that provided the item to this device. |
ItemIsDeliveredEvent |
ItemIsDeliveredEvent<public>:listenable(agent) |
Signaled when an item is delivered to this device. Sends the agent that delivered the item to this 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. |
ToggleEnabled |
ToggleEnabled<public>():void |
Toggles between Enable and Disable. |
AllowCapture |
AllowCapture<public>():void |
Allows this device to be captured. |
DisallowCapture |
DisallowCapture<public>():void |
Disallows this device from being captured. |
ToggleCaptureAllowed |
ToggleCaptureAllowed<public>():void |
Toggles between AllowCapture and DisallowCapture. |
GiveControl |
GiveControl<public>(Agent:agent):void |
Gives control of this device to the capturing agent's team. |
Neutralize |
Neutralize<public>():void |
Clears control of this device for all teams. |
ActivateObjectivePulse |
ActivateObjectivePulse<public>():void |
Activates the objective pulse for this device. |
DeactivateObjectivePulse |
DeactivateObjectivePulse<public>():void |
Deactivates the objective pulse for this device. |
SetHeight |
SetHeight<public>(Height:float):void |
Sets the Capture Height (in meters) of the capture area. |
GetHeight |
GetHeight<public>()<reads>:float |
Returns the Capture Height (in meters) of the capture area. |
SetRadius |
SetRadius<public>(Radius:float):void |
Sets the Capture Radius (in meters) of the capture area. |
GetRadius |
GetRadius<public>()<reads>:float |
Returns the Capture Radius (in meters) of the capture area. |
GetAgentsInVolume |
GetAgentsInVolume<public>()<reads>:[]agent |
Returns an array of agents that are currently occupying the Capture Area. |
IsInArea |
IsInArea<public>(Agent:agent)<transacts><decides>:void |
Is true when Agent is in the Capture Area. |
Walkthrough
Scenario — Three-Point Domination
You have three capture areas (A, B, C) on a map. A Verse device manages all three:
- When a point is first entered it pulses its objective marker so enemies know it's being contested.
- When control changes it prints a message and removes the pulse.
- When the last player leaves it neutralizes the point so neither team holds it passively.
- A helper method lets a designer resize any point at runtime (e.g., shrink it during a final round).
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Localized message helper
PointCapturedMsg<localizes>(PointName : string) : message = "Point {PointName} has been captured!"
PointContestedMsg<localizes>(PointName : string) : message = "Point {PointName} is being contested!"
PointNeutralizedMsg<localizes>() : message = "A point has been neutralized!"
domination_manager := class(creative_device):
# Wire these to your three placed Capture Area devices in the Details panel
@editable
CaptureAreaA : capture_area_device = capture_area_device{}
@editable
CaptureAreaB : capture_area_device = capture_area_device{}
@editable
CaptureAreaC : capture_area_device = capture_area_device{}
# Called once at game start — subscribe to all relevant events
OnBegin<override>()<suspends> : void =
# Point A
CaptureAreaA.FirstAgentEntersEvent.Subscribe(OnFirstEntersA)
CaptureAreaA.ControlChangeEvent.Subscribe(OnControlChangedA)
CaptureAreaA.LastAgentExitsEvent.Subscribe(OnLastExitsA)
CaptureAreaA.AreaIsContestedEvent.Subscribe(OnContestedA)
# Point B
CaptureAreaB.FirstAgentEntersEvent.Subscribe(OnFirstEntersB)
CaptureAreaB.ControlChangeEvent.Subscribe(OnControlChangedB)
CaptureAreaB.LastAgentExitsEvent.Subscribe(OnLastExitsB)
# Point C
CaptureAreaC.FirstAgentEntersEvent.Subscribe(OnFirstEntersC)
CaptureAreaC.ControlChangeEvent.Subscribe(OnControlChangedC)
CaptureAreaC.LastAgentExitsEvent.Subscribe(OnLastExitsC)
# Activate objective pulses at game start so players know where the points are
CaptureAreaA.ActivateObjectivePulse()
CaptureAreaB.ActivateObjectivePulse()
CaptureAreaC.ActivateObjectivePulse()
# ── Point A handlers ──────────────────────────────────────────────────────
OnFirstEntersA(Agent : agent) : void =
# Someone just walked in — pulse so enemies see it's being contested
CaptureAreaA.ActivateObjectivePulse()
OnControlChangedA(Agent : agent) : void =
# A team now owns the point — stop pulsing, it's captured
CaptureAreaA.DeactivateObjectivePulse()
OnLastExitsA(Agent : agent) : void =
# Nobody left inside — neutralize so it doesn't stay owned passively
CaptureAreaA.Neutralize()
CaptureAreaA.ActivateObjectivePulse() # pulse again so players come back
OnContestedA(Agent : agent) : void =
# Optionally re-pulse when contested (enemy entered an owned point)
CaptureAreaA.ActivateObjectivePulse()
# ── Point B handlers ──────────────────────────────────────────────────────
OnFirstEntersB(Agent : agent) : void =
CaptureAreaB.ActivateObjectivePulse()
OnControlChangedB(Agent : agent) : void =
CaptureAreaB.DeactivateObjectivePulse()
OnLastExitsB(Agent : agent) : void =
CaptureAreaB.Neutralize()
CaptureAreaB.ActivateObjectivePulse()
# ── Point C handlers ──────────────────────────────────────────────────────
OnFirstEntersC(Agent : agent) : void =
CaptureAreaC.ActivateObjectivePulse()
OnControlChangedC(Agent : agent) : void =
CaptureAreaC.DeactivateObjectivePulse()
OnLastExitsC(Agent : agent) : void =
CaptureAreaC.Neutralize()
CaptureAreaC.ActivateObjectivePulse()
# ── Designer helper — call from another device or a timer ─────────────────
# Shrinks all three points to create a tighter final-round zone
ShrinkAllPoints() : void =
CaptureAreaA.SetRadius(3.0)
CaptureAreaA.SetHeight(2.0)
CaptureAreaB.SetRadius(3.0)
CaptureAreaB.SetHeight(2.0)
CaptureAreaC.SetRadius(3.0)
CaptureAreaC.SetHeight(2.0)
Line-by-line highlights:
| Line / block | What it does |
|---|---|
@editable fields |
Lets you drag real placed devices into the slots in the UEFN Details panel. Without @editable you can't reference a placed device. |
FirstAgentEntersEvent.Subscribe |
Fires once when the zone goes from empty → occupied. Perfect for "contest starts" logic. |
LastAgentExitsEvent.Subscribe |
Fires once when the zone goes from occupied → empty. Ideal for auto-neutralize. |
ControlChangeEvent.Subscribe |
Fires when ownership flips to a new team. |
ActivateObjectivePulse() / DeactivateObjectivePulse() |
Toggles the glowing objective ring players see on-screen. |
Neutralize() |
Clears team ownership so the point is up for grabs again. |
SetRadius(3.0) / SetHeight(2.0) |
Resizes the cylinder at runtime — great for dynamic round phases. |
Common patterns
Pattern 1 — Automatic Proximity Door
Use FirstAgentEntersEvent / LastAgentExitsEvent to open and close a door. The capture area sits in the doorway; no capture settings needed.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
auto_door_device := class(creative_device):
@editable
DoorZone : capture_area_device = capture_area_device{}
# A mutator zone or prop manipulator would be the real door;
# here we use a second capture area as a stand-in for illustration.
@editable
InnerDoorZone : capture_area_device = capture_area_device{}
OnBegin<override>()<suspends> : void =
# Disable capture so this zone is purely a proximity sensor
DoorZone.DisallowCapture()
DoorZone.FirstAgentEntersEvent.Subscribe(OnSomeonePproaches)
DoorZone.LastAgentExitsEvent.Subscribe(OnEveryoneLeaves)
OnSomeonePproaches(Agent : agent) : void =
# "Open" the door — enable the inner zone or trigger your door prop
InnerDoorZone.Enable()
OnEveryoneLeaves(Agent : agent) : void =
# "Close" the door after the last person leaves
InnerDoorZone.Disable()
Key calls: DisallowCapture() turns off the scoring system so the zone is a pure sensor. Enable() / Disable() on a second device acts as the door actuator.
Pattern 2 — Head-Count Gate (IsInArea + GetAgentsInVolume)
Only unlock a vault when three or more players are standing in the zone simultaneously — a co-op puzzle mechanic.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_gate_device := class(creative_device):
@editable
PressurePlate : capture_area_device = capture_area_device{}
@editable
VaultDoor : capture_area_device = capture_area_device{}
# Minimum players required to open the vault
RequiredPlayers : int = 3
OnBegin<override>()<suspends> : void =
PressurePlate.DisallowCapture()
VaultDoor.Disable() # vault starts locked
# Check the count every time someone enters or exits
PressurePlate.AgentEntersEvent.Subscribe(OnZoneChanged)
PressurePlate.AgentExitsEvent.Subscribe(OnZoneChanged)
OnZoneChanged(Agent : agent) : void =
Agents := PressurePlate.GetAgentsInVolume()
if (Agents.Length >= RequiredPlayers):
VaultDoor.Enable() # enough players — open the vault
else:
VaultDoor.Disable() # too few — keep it locked
Key calls: GetAgentsInVolume() returns the live slice of agents inside right now. AgentEntersEvent and AgentExitsEvent (not just First/Last) fire for every individual, so the count is always fresh.
Pattern 3 — Neutralize Event + GiveControl (Flag Delivery)
When a flag carrier delivers an item, immediately give control to their team and then neutralize after a delay — simulating a timed capture in a CTF variant.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
ctf_delivery_zone := class(creative_device):
@editable
DeliveryZone : capture_area_device = capture_area_device{}
OnBegin<override>()<suspends> : void =
DeliveryZone.ItemIsDeliveredEvent.Subscribe(OnFlagDelivered)
DeliveryZone.NeutralizeEvent.Subscribe(OnZoneNeutralized)
OnFlagDelivered(Agent : agent) : void =
# Hand control to the delivering agent's team immediately
DeliveryZone.GiveControl(Agent)
# Wait 10 seconds, then reset the zone for the next round
Sleep(10.0)
DeliveryZone.Neutralize()
# NeutralizeEvent sends ?agent — must unwrap the option
OnZoneNeutralized(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
# A specific agent triggered the neutralize
DeliveryZone.ActivateObjectivePulse()
else:
# Neutralized programmatically (no agent responsible)
DeliveryZone.ActivateObjectivePulse()
Key calls: ItemIsDeliveredEvent fires when a player drops a tracked item (flag) into the zone. GiveControl(Agent) skips the capture progress bar and instantly awards the point. NeutralizeEvent sends ?agent — always unwrap with if (A := MaybeAgent?).
Gotchas
1. NeutralizeEvent sends ?agent, not agent
Every other event on this device sends a plain agent. NeutralizeEvent sends ?agent (optional) because the neutralize can be triggered programmatically with no player involved. Always unwrap:
OnNeutralized(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
# use A as a real agent
Forgetting this causes a type mismatch compile error.
2. @editable is mandatory for placed devices
You cannot write MyArea := capture_area_device{} and expect it to refer to the device you placed in the level. That creates a new, unplaced instance. Every device you want to control from Verse must be declared as an @editable field and then dragged into the slot in the UEFN Details panel.
3. DisallowCapture() before using as a pure sensor
If you use a capture area purely as a proximity trigger (door, head-count gate, etc.) and leave Capture enabled in the Details panel, the zone will still run its scoring logic, fire ControlChangeEvent, and potentially award score. Call DisallowCapture() in OnBegin to suppress all of that.
4. IsInArea has <transacts><decides> effects
IsInArea is a failable expression — it only succeeds if the agent is inside. You must call it inside an if (or another decision context):
# Correct
if (DeliveryZone.IsInArea[SomeAgent]):
# agent is confirmed inside
Calling it outside a decision context is a compile error.
5. SetRadius / SetHeight take float, not int
Verse does not auto-convert integers to floats. Write SetRadius(5.0) not SetRadius(5) — the latter is a type error.
6. Objective pulse state is not automatically reset
ActivateObjectivePulse() and DeactivateObjectivePulse() are fire-and-forget toggles. If you Disable() the device and then Enable() it again, the pulse state is whatever you last set it to. Re-activate or deactivate explicitly after re-enabling.
7. GiveControl bypasses the capture progress bar
This is intentional for scripted scenarios (flag delivery, designer-triggered events), but if you call it mid-contest the progress bar will snap immediately. Pair it with ControlChangeStartsEvent if you need to animate a transition in your UI.