Overview
Abs() is one of Verse's intrinsic math functions. It returns the absolute value of a number — its distance from zero, with the sign thrown away. Abs(-7.0) is 7.0; Abs(7.0) is also 7.0.
Why does a game care? Because positions can be left or right, above or below, ahead or behind a target. When you subtract two coordinates you get a signed difference — negative if the player is on one side, positive on the other. If all you want is "how far apart are they?", you wrap the subtraction in Abs() and stop worrying about which direction.
On our sunny cove, that lets us fire a trigger_device when a player stands close to a treasure chest along the dock's X axis — approaching from the bow or the stern both count. Abs() works on both int and float; the vector components we read off positions are float, so we work in floats. Reach for Abs() whenever you need a magnitude — a gap, a delta, a tolerance — rather than a signed offset.
API Reference
vector3
3-dimensional vector with
floatcomponents.
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse).
vector3<native><public> := struct<concrete><computes><persistable><uht_comparable>:
trigger_device
Used to relay events to other linked devices.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from trigger_base_device.
trigger_device<public> := class<concrete><final>(trigger_base_device):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
TriggeredEvent |
TriggeredEvent<public>:listenable(?agent) |
Signaled when an agent triggers this device. Sends the agent that used this device. Returns false if no agent triggered the action (ex: it was triggered through code). |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Trigger |
Trigger<public>(Agent:agent):void |
Triggers this device with Agent being passed as the agent that triggered the action. Use an agent reference when this device is setup to require one (for instance, you want to trigger the device only with a particular agent. |
Trigger |
Trigger<public>():void |
Triggers this device, causing it to activate its TriggeredEvent event. |
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
SetMaxTriggerCount |
SetMaxTriggerCount<public>(MaxCount:int):void |
Sets the maximum amount of times this device can trigger. * 0 can be used to indicate no limit on trigger count. * MaxCount is clamped between [0,20]. |
GetMaxTriggerCount |
GetMaxTriggerCount<public>()<transacts>:int |
Gets the maximum amount of times this device can trigger. * 0 indicates no limit on trigger count. |
GetTriggerCountRemaining |
GetTriggerCountRemaining<public>()<transacts>:int |
Returns the number of times that this device can still be triggered before hitting GetMaxTriggerCount. Returns 0 if GetMaxTriggerCount is unlimited. |
SetResetDelay |
SetResetDelay<public>(Time:float):void |
Sets the time (in seconds) after triggering, before the device can be triggered again (if MaxTrigger count allows). |
GetResetDelay |
GetResetDelay<public>()<transacts>:float |
Gets the time (in seconds) before the device can be triggered again (if MaxTrigger count allows). |
SetTransmitDelay |
SetTransmitDelay<public>(Time:float):void |
Sets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered. |
GetTransmitDelay |
GetTransmitDelay<public>()<transacts>:float |
Gets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered. |
player
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from agent.
player<native><public> := class<unique><persistent><module_scoped_var_weak_map_key><epic_internal>(agent):
Walkthrough
Here's the full cove scene. A vector3 marks where the treasure chest sits on the dock. Every tick we compare each player's X position against the chest's X. If the absolute difference is within our tolerance, we Trigger() the device — which might open a vault, play a jingle, or spawn loot via whatever you've wired to it. We also cap it with SetMaxTriggerCount so the chest only pops once, and give it a reset delay so it can re-arm.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
cove_treasure_device := class(creative_device):
# The trigger wired to your chest / loot / jingle in the editor.
@editable
ChestTrigger : trigger_device = trigger_device{}
# Where the treasure sits on the dock (set in Details panel).
@editable
ChestSpot : vector3 = vector3{ X := 0.0, Y := 0.0, Z := 0.0 }
# How close (in cm along X) counts as "at the chest".
@editable
Tolerance : float = 200.0
OnBegin<override>()<suspends>:void =
# Only let the chest pop a single time, then re-arm after 3s.
ChestTrigger.SetMaxTriggerCount(1)
ChestTrigger.SetResetDelay(3.0)
ChestTrigger.Enable()
# Watch the shore forever, checking each player every tick.
loop:
CheckPlayers()
Sleep(0.0)
CheckPlayers()<suspends>:void =
for (Player : GetPlayspace().GetPlayers()):
if (Char := Player.GetFortCharacter[]):
Pos := Char.GetTransform().Translation
# Signed gap could be negative (player west of chest)
# or positive (east of chest). Abs() ignores the side.
GapX := Abs(Pos.X - ChestSpot.X)
if (GapX <= Tolerance):
# Fire the trigger, crediting this player.
ChestTrigger.Trigger(Player)```
Line by line:
- The `@editable` fields let you drop the real `trigger_device` onto the field in the Details panel, and set the chest's spot and tolerance without touching code.
- `SetMaxTriggerCount(1)` means the chest can only be looted once; `SetResetDelay(3.0)` lets it re-arm after three seconds so a second player can loot it.
- In `OnBegin` the `loop` with `Sleep(0.0)` runs our check once per frame without hogging the CPU.
- `GetFortCharacter[]` is a failable lookup — if the player isn't spawned yet, the `if` simply skips them.
- `Pos.X - ChestSpot.X` is the *signed* difference. Wrapping it in `Abs()` turns "5 metres west" and "5 metres east" into the same `500.0`.
- `ChestTrigger.Trigger(Player)` activates the device and passes the player as the triggering `agent`, so anything listening on `TriggeredEvent` knows who did it.
## Common patterns
**Pattern 1 — React on TriggeredEvent and unwrap the agent.** Subscribe to the trigger's event to run loot logic, using `Abs()` to log how far off-centre the looter stood.
```verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
cove_loot_listener := class(creative_device):
@editable
ChestTrigger : trigger_device = trigger_device{}
@editable
ChestSpot : vector3 = vector3{ X := 0.0, Y := 0.0, Z := 0.0 }
OnBegin<override>()<suspends>:void =
ChestTrigger.TriggeredEvent.Subscribe(OnLooted)
OnLooted(Agent : ?agent):void =
if (A := Agent?):
if (Player := player[A], Char := A.GetFortCharacter[]):
Pos := Char.GetTransform().Translation
# How far off-centre (any direction) the looter stood.
OffCentre := Abs(Pos.Y - ChestSpot.Y)
if (OffCentre < 100.0):
# Dead-centre bonus loot could go here.
ChestTrigger.Trigger()
Pattern 2 — Tune re-arm timing and read remaining triggers. Use the getter/setter pair around trigger counts so a limited-supply chest slows down as it empties.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
cove_supply_chest := class(creative_device):
@editable
ChestTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
ChestTrigger.SetMaxTriggerCount(5)
ChestTrigger.Enable()
loop:
Remaining := ChestTrigger.GetTriggerCountRemaining()
# Fewer supplies left => longer cooldown, using Abs()
# as a tidy magnitude so the delay never goes negative.
NewDelay := Abs(5.0 - Int[Remaining] * 1.0)
ChestTrigger.SetResetDelay(NewDelay)
Sleep(2.0)
Pattern 3 — Disable the chest when it's empty. Combine GetMaxTriggerCount, GetTriggerCountRemaining, and Disable() so an exhausted chest goes dark.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
cove_chest_watcher := class(creative_device):
@editable
ChestTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
ChestTrigger.SetMaxTriggerCount(3)
ChestTrigger.Enable()
loop:
Max := ChestTrigger.GetMaxTriggerCount()
Left := ChestTrigger.GetTriggerCountRemaining()
# Distance from empty. When 0, the chest is spent.
Used := Abs(Max - Left)
if (Left <= 0 && Max > 0):
ChestTrigger.Disable()
Sleep(1.0)
Gotchas
- No int↔float auto-convert.
vector3components arefloat, so subtract floats and compare against afloattolerance. In Pattern 2,GetTriggerCountRemaining()returns anint, so we bridge it withInt[Remaining] * 1.0before mixing with a float — you can't add anintto afloatdirectly. Abs()doesn't change the type.Abs(anInt)returns anint;Abs(aFloat)returns afloat. Keep your types consistent on both sides of a comparison.Trigger()vsTrigger(Agent). The no-arg overload fires the device butTriggeredEventmay report no agent. Pass the player when you needTriggeredEventhandlers to know who triggered it — then unwrap withif (A := Agent?):.- The event payload is
?agent, notagent. Your handler signature must be(Agent : ?agent)and you must unwrap it before use. To get aplayer, narrow withplayer[A]. GetFortCharacter[]can fail. A player who just joined or respawned may not have a character yet — always guard the lookup withifso the loop skips them instead of crashing.SetMaxTriggerCountis clamped to [0,20]. Ask for 100 and you'll silently get 20;0means unlimited.SetResetDelaymust be non-negative. Feeding it a raw signed subtraction can go negative — wrapping the value inAbs(), as in Pattern 2, keeps the delay sane.