Overview
Verse uses the logic type to represent Boolean values. A logic variable can hold exactly one of two values: true or false. This is the foundation of every conditional branch, every gate, every "has the player done X yet?" check in your island.
You reach for logic whenever you need to:
- Track a game-state flag ("has the vault been opened?", "is the round active?")
- Combine multiple conditions before allowing an action (
and,or,not) - Drive device behaviour — enabling or disabling a
barrier_device, branching on team membership, etc. - Avoid running the same setup twice with a simple guard variable
The logic type is not a number. You cannot add or subtract it. You test it with the ? (query) operator inside a failure context like if, or with and/or/not expressions. The result of a query is either success (the expression continues) or failure (the branch is skipped).
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: A two-team box-fight arena. Team 1 stands on a pressure plate. When they do, a central barrier drops so both teams can fight. A logic flag prevents the barrier from being disabled a second time if the event fires again.
The barrier_device is the real UEFN device we control here. We use Enable() and Disable() — the two core methods on barrier_device — driven entirely by logic state.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# A two-team arena: stepping on the plate drops the central barrier.
# A logic flag ensures we only drop it once per round.
box_fight_manager := class<concrete>(creative_device):
# Wire these up in the UEFN editor via the @editable properties panel.
@editable
CentralBarrier : barrier_device = barrier_device{}
@editable
StartPlate : trigger_device = trigger_device{}
# Boolean flag: has the barrier already been dropped this round?
var BarrierDropped : logic = false
OnBegin<override>()<suspends> : void =
# Subscribe: whenever a player steps on the plate, call OnPlateTriggered.
StartPlate.TriggeredEvent.Subscribe(OnPlateTriggered)
# Make sure the barrier starts enabled (blocking movement).
CentralBarrier.Enable()
# Handler receives an optional agent — the player who triggered the plate.
OnPlateTriggered(Agent : ?agent) : void =
# Guard: only act if the barrier has NOT been dropped yet.
if (not BarrierDropped?):
# Mark it dropped so this branch never runs again this round.
set BarrierDropped = true
# Drop the barrier — both teams can now engage.
CentralBarrier.Disable()
# Call this to reset the arena for a new round.
ResetArena() : void =
set BarrierDropped = false
CentralBarrier.Enable()
Line-by-line explanation:
| Line | What it does |
|---|---|
var BarrierDropped : logic = false |
Declares a mutable Boolean flag, starting as false. The var keyword makes it reassignable. |
StartPlate.TriggeredEvent.Subscribe(OnPlateTriggered) |
Wires the plate's event to our handler at runtime. |
CentralBarrier.Enable() |
Ensures the barrier is solid at round start. |
OnPlateTriggered(Agent : ?agent) |
Event handlers for trigger_device receive ?agent (an optional agent). We don't need to unwrap it here because our logic doesn't use the player identity. |
if (not BarrierDropped?): |
The ? operator queries the logic value. not inverts the result. If BarrierDropped is false, BarrierDropped? fails, not turns that into success, so the if body runs. |
set BarrierDropped = true |
Flips the flag so subsequent plate triggers do nothing. |
CentralBarrier.Disable() |
The real device call — drops the barrier. |
ResetArena() |
Resets both the flag and the physical barrier for the next round. |
Common patterns
Pattern 1 — Combining conditions with and before acting
Two barriers must BOTH be active before we allow a reset. We combine two logic variables with and.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# Only re-enable the exit barrier when BOTH checkpoints are cleared.
dual_checkpoint_manager := class<concrete>(creative_device):
@editable
ExitBarrier : barrier_device = barrier_device{}
@editable
CheckpointA : trigger_device = trigger_device{}
@editable
CheckpointB : trigger_device = trigger_device{}
var CheckpointACleared : logic = false
var CheckpointBCleared : logic = false
OnBegin<override>()<suspends> : void =
ExitBarrier.Enable()
CheckpointA.TriggeredEvent.Subscribe(OnCheckpointA)
CheckpointB.TriggeredEvent.Subscribe(OnCheckpointB)
OnCheckpointA(Agent : ?agent) : void =
set CheckpointACleared = true
MaybeOpenExit()
OnCheckpointB(Agent : ?agent) : void =
set CheckpointBCleared = true
MaybeOpenExit()
# Only open the exit when BOTH flags are true.
MaybeOpenExit() : void =
if (CheckpointACleared? and CheckpointBCleared?):
ExitBarrier.Disable()
Key idea: CheckpointACleared? and CheckpointBCleared? — both query expressions must succeed for the if body to run. Short-circuit evaluation means if the first fails, the second is never tested.
Pattern 2 — Using logic{} to convert a failable expression into a value
Sometimes you want to store the result of a test as a logic value rather than branching immediately. logic{} wraps a failable expression and produces true on success or false on failure.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# Decide at setup time whether the barrier should start open or closed,
# based on a configurable threshold.
vault_gate_manager := class<concrete>(creative_device):
@editable
VaultBarrier : barrier_device = barrier_device{}
# Set this in the editor: 0 = always closed, 1 = always open.
@editable
var OpenOnStart : logic = false
OnBegin<override>()<suspends> : void =
# Use the stored logic value directly to decide initial state.
if (OpenOnStart?):
VaultBarrier.Disable() # Start open
else:
VaultBarrier.Enable() # Start closed
# Toggle: flip the current state and apply it to the barrier.
ToggleVault(CurrentlyOpen : logic) : void =
# logic{} converts the query result to a logic value.
var NextState : logic = logic{not CurrentlyOpen?}
if (NextState?):
VaultBarrier.Disable()
else:
VaultBarrier.Enable()
Key idea: logic{not CurrentlyOpen?} — the logic{} expression evaluates the failable not CurrentlyOpen? and stores true or false as a concrete logic value you can pass around or store in a variable.
Pattern 3 — Per-agent ignore list driven by a logic flag
barrier_device has AddToIgnoreList and RemoveFromIgnoreList. We use a logic flag to track whether a specific player is currently on the VIP pass list, and toggle them in and out.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# A VIP barrier: certain players can walk through; others are blocked.
# A logic flag per-session tracks whether VIP access is active.
vip_barrier_manager := class<concrete>(creative_device):
@editable
VIPBarrier : barrier_device = barrier_device{}
@editable
VIPPlate : trigger_device = trigger_device{}
@editable
RevokeButton : button_device = button_device{}
var VIPAccessGranted : logic = false
OnBegin<override>()<suspends> : void =
VIPBarrier.Enable()
VIPPlate.TriggeredEvent.Subscribe(OnVIPPlateTriggered)
RevokeButton.InteractedWithEvent.Subscribe(OnRevokePressed)
OnVIPPlateTriggered(MaybeAgent : ?agent) : void =
# Unwrap the optional agent before using them.
if (A := MaybeAgent?):
if (not VIPAccessGranted?):
set VIPAccessGranted = true
# This agent can now pass through the barrier.
VIPBarrier.AddToIgnoreList(A)
OnRevokePressed(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (VIPAccessGranted?):
set VIPAccessGranted = false
VIPBarrier.RemoveFromIgnoreList(A)
Key idea: We unwrap ?agent with if (A := MaybeAgent?): before passing the agent to AddToIgnoreList / RemoveFromIgnoreList. The logic flag prevents double-adding the same agent.
Gotchas
1. logic is NOT a number — no arithmetic
# WRONG — this does not compile:
var Count : int = 0
if (Count + IsReady): # type error: int and logic are incompatible
You cannot add, subtract, or compare logic with numbers. Test it with ? inside a failure context only.
2. The ? query operator only works inside a failure context
? is a failable expression. It must appear inside if, and/or, logic{}, or another failure context. Calling MyFlag? as a standalone statement is a compile error.
# WRONG:
MyFlag? # standalone query — not in a failure context, won't compile
# RIGHT:
if (MyFlag?): DoSomething()
3. Mutable logic variables require var and set
Without var, the variable is immutable. Without set, the assignment fails to compile.
# WRONG — immutable, cannot reassign:
BarrierDropped : logic = false
BarrierDropped = true # compile error
# RIGHT:
var BarrierDropped : logic = false
set BarrierDropped = true
4. not inverts a failable expression, not a value
not wraps a failable expression and inverts its success/failure. It does NOT take a logic value directly — it takes a failable expression that produces success or failure.
# Correct usage — BarrierDropped? is a failable expression:
if (not BarrierDropped?): DoSetup()
# Also correct — logic{} converts to a stored value first:
var Inverted : logic = logic{not BarrierDropped?}
5. barrier_device ignore list does NOT affect bullets
The Epic docs explicitly note: AddToIgnoreList lets an agent walk through the barrier, but bullets still collide. If you need bullet pass-through, you must Disable the barrier entirely rather than relying on the ignore list.