Overview
The ai_patrol_path_device is the brain behind a guard's walking route. You place several of these node devices around your map, group them under a shared Patrol Path Group number, and guards spawned by a guard_spawner_device (with a matching Spawn on Patrol Path Group) will walk between them automatically.
Where it really earns its keep is at runtime. From Verse you can:
Assign(Patroller)— hand a specific guard to this patrol path on the fly (great for redirecting reinforcements).GoToNextPatrolGroup(Patroller)— bump a guard onto its Next Patrol Path Group, e.g. switch a guard from a calm loop to an alert sweep.Enable()/Disable()— turn a node on or off so guards skip or include it.- Subscribe to
NodeReachedEvent,NextNodeUnreachableEvent,PatrolPathStartedEvent, andPatrolPathStoppedEventto drive game logic — open a door when a guard reaches the gate node, raise an alarm if a guard gets stuck, etc.
Reach for this device whenever you want living, moving guards that feel like they're protecting something — a vault, a checkpoint, a treasure room — instead of standing still.
API Reference
ai_patrol_path_device
Used to create patrolling behavior for guards spawned with the
guard_spawner_device.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
ai_patrol_path_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
NodeReachedEvent |
NodeReachedEvent<public>:listenable(agent) |
Signaled when a guard reaches this device. |
NextNodeUnreachableEvent |
NextNodeUnreachableEvent<public>:listenable(agent) |
Signaled when a guard cannot reach the next ai_patrol_path_device. |
PatrolPathStartedEvent |
PatrolPathStartedEvent<public>:listenable(agent) |
Signaled when a guard starts moving on the patrol path. |
PatrolPathStoppedEvent |
PatrolPathStoppedEvent<public>:listenable(agent) |
Signaled when a guard stops moving on the patrol path. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Assign |
Assign<public>(Patroller:agent):void |
Assign an AI to this patrol path. |
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
GoToNextPatrolGroup |
GoToNextPatrolGroup<public>(Patroller:agent):void |
Commands patroller to follow the Next Patrol Path Group instead of the default Patrol Path Group. |
Walkthrough
Scenario: A vault is guarded by a single sentry that loops between patrol nodes. When the guard reaches the gate node (this patrol device), we light up a prop and a HUD message. If the guard ever can't reach the next node (path blocked), we log an alert. And once the round starts, we explicitly assign the spawned guard to the path and command it to switch to its alert route.
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Fortnite.com/AI }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
vault_patrol_manager := class(creative_device):
# The patrol node we react to (place it at the vault gate).
@editable
GatePatrolNode : ai_patrol_path_device = ai_patrol_path_device{}
# The spawner that produces our guard.
@editable
GuardSpawner : guard_spawner_device = guard_spawner_device{}
# A prop or device we light up when the guard arrives.
@editable
ArrivalLight : prop_mover_device = prop_mover_device{}
# Localized message helper (message params need a localized value, not a raw string).
StatusText<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
# React when the guard reaches THIS node.
GatePatrolNode.NodeReachedEvent.Subscribe(OnNodeReached)
# React when the next node can't be reached (blocked path).
GatePatrolNode.NextNodeUnreachableEvent.Subscribe(OnNextUnreachable)
# React when a guard starts / stops moving on the path.
GatePatrolNode.PatrolPathStartedEvent.Subscribe(OnPatrolStarted)
GatePatrolNode.PatrolPathStoppedEvent.Subscribe(OnPatrolStopped)
# When the spawner produces a guard, wire it to our path.
GuardSpawner.SpawnedEvent.Subscribe(OnGuardSpawned)
# Make sure the node is active.
GatePatrolNode.Enable()
# Spawner hands us the new guard agent.
OnGuardSpawned(Guard : agent) : void =
# Assign this fresh guard to our patrol path.
GatePatrolNode.Assign(Guard)
# Immediately send it onto its ALERT route (the Next Patrol Path Group).
GatePatrolNode.GoToNextPatrolGroup(Guard)
OnNodeReached(Agent : agent) : void =
# The guard hit the gate node — trigger the arrival light.
ArrivalLight.Begin()
OnNextUnreachable(Agent : agent) : void =
# Path blocked: turn the node off so guards re-route past it.
GatePatrolNode.Disable()
OnPatrolStarted(Agent : agent) : void =
ArrivalLight.End()
OnPatrolStopped(Agent : agent) : void =
# Guard stopped on the path; nothing dramatic, but we could escalate here.
ArrivalLight.End()
Line by line:
GatePatrolNode,GuardSpawner,ArrivalLightare@editablefields — you must declare a placed device as a field of acreative_deviceclass before you can call its methods. A bareDevice.Method()fails with 'Unknown identifier'.- In
OnBegin, everySubscribe(...)wires a class method as the handler. Patrol events arelistenable(agent), so each handler receives a singleAgent : agent. OnGuardSpawnedis called by the spawner'sSpawnedEvent. WeAssignthe new guard to the node, thenGoToNextPatrolGroupto push it onto the alternate (alert) route.OnNodeReachedfires the moment the guard reaches the gate node — we play the arrival light withBegin().OnNextUnreachablehandles a blocked path byDisable()-ing the node so the AI re-routes.Enable()at the end ofOnBeginguarantees the node is live when the round starts.
Common patterns
1. Redirect a specific player-hired guard onto a chase route with GoToNextPatrolGroup. When a player trips a trigger, switch the patrol to its alert group.
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Fortnite.com/AI }
using { /Verse.org/Simulation }
alert_switcher := class(creative_device):
@editable
PatrolNode : ai_patrol_path_device = ai_patrol_path_device{}
@editable
GuardSpawner : guard_spawner_device = guard_spawner_device{}
@editable
AlarmTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
AlarmTrigger.TriggeredEvent.Subscribe(OnAlarm)
OnAlarm(MaybeAgent : ?agent) : void =
# The trigger hands us an optional agent; we don't need it here.
# Push every spawned guard onto the alert route.
for (Guard : GuardSpawner.GetAgents()):
PatrolNode.GoToNextPatrolGroup(Guard)
2. Toggle a checkpoint node on and off with Enable / Disable. A button opens or seals a patrol leg.
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
checkpoint_toggle := class(creative_device):
@editable
CheckpointNode : ai_patrol_path_device = ai_patrol_path_device{}
@editable
OpenButton : button_device = button_device{}
@editable
CloseButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
OpenButton.InteractedWithEvent.Subscribe(OnOpen)
CloseButton.InteractedWithEvent.Subscribe(OnClose)
OnOpen(Agent : agent) : void =
CheckpointNode.Enable()
OnClose(Agent : agent) : void =
CheckpointNode.Disable()
3. Count nodes reached to escalate an alarm using NodeReachedEvent. After the guard completes its loop a set number of times, fire an alarm device.
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
patrol_counter := class(creative_device):
@editable
LoopNode : ai_patrol_path_device = ai_patrol_path_device{}
@editable
AlarmHud : hud_message_device = hud_message_device{}
var ReachedCount : int = 0
OnBegin<override>()<suspends> : void =
LoopNode.NodeReachedEvent.Subscribe(OnReached)
OnReached(Agent : agent) : void =
set ReachedCount = ReachedCount + 1
if (ReachedCount >= 3):
AlarmHud.Show()
set ReachedCount = 0
Gotchas
- You can't call a device without a field.
ai_patrol_path_device.Assign(...)straight up won't compile — declare an@editablefield and call the method on that instance. - Patrol events deliver a non-optional
agent.NodeReachedEventand friends arelistenable(agent), so your handler signature is(Agent : agent)— no?to unwrap. Contrast with atrigger_device.TriggeredEvent, which hands you(MaybeAgent : ?agent)that you DO need to unwrap withif (A := MaybeAgent?):. - Group numbers must match.
GoToNextPatrolGroupdoes nothing useful unless the device's Next Patrol Path Group and the destination nodes share that group number. Set these in the device's details panel — Verse only triggers the switch. Assignneeds a spawned AI agent. Pass an agent that actually came from theguard_spawner_device(useSpawnedEventorGetAgents()); assigning a player agent won't make a guard patrol.messageparams need a localized value. If you pass a guard's name or status into a HUD device, build it with a<localizes>helper likeStatusText<localizes>(S:string):message = "{S}"— there is noStringToMessage.- Disable doesn't delete the guard.
Disable()only takes the node out of the route; the guard keeps moving along the remaining active nodes. Re-Enable()to fold it back in.