Overview
On a bright, cel-shaded pirate cove, you constantly deal with values that must stay inside a range. The cannon's elevation should live between 0° and 60°. The treasure-hunt meter should never drop below 0 or climb past its max. A player's boost speed should be capped so they don't rocket off the dock.
That's exactly what Clamp does: it takes a value and two bounds and returns the value squeezed into [A, B]. Its integer siblings Min and Max pick the smaller or larger of two whole numbers — perfect for counting collected doubloons or capping a wave counter.
Reach for these when:
- A running total could overshoot a limit (score, meter, ammo).
- You compute a position/angle/speed and need to keep it sane.
- You want "never below zero" or "never above max" in one clean line.
These are built-in Verse math functions, not placed devices. You call them directly from any Verse code — no @editable field required for the math itself (though you still declare devices you want to drive with the result).
API Reference
(API surface could not be resolved for this device.)
Walkthrough
The scene: A sunny lagoon dock. Players step on a trigger plate to "crank" a treasure-hunt meter upward. Each crank adds points, but the meter caps at 100 — and if you idle, it drifts back down but never below 0. We drive a real hud_message_device to show the clamped value.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
using { /UnrealEngine.com/Temporary/SpatialMath }
# A localized-text helper: `message` params need this, not a raw string.
treasure_text<localizes>(S : string) : message = "{S}"
treasure_meter := class(creative_device):
# The plate players step on to crank the meter up.
@editable
CrankPlate : trigger_device = trigger_device{}
# Shows the current clamped meter value to players.
@editable
MeterHud : hud_message_device = hud_message_device{}
# The raw, unclamped running total. Can drift out of range...
var RawMeter : float = 0.0
# ...but this is what we actually show, always inside [0, 100].
MeterMin : float = 0.0
MeterMax : float = 100.0
OnBegin<override>()<suspends>:void =
# Each step on the plate cranks the meter.
CrankPlate.TriggeredEvent.Subscribe(OnCrank)
# Run a slow drift-down loop in the background.
spawn{ DriftLoop() }
OnCrank(Agent : ?agent) : void =
# Add a chunk of progress to the raw total.
set RawMeter = RawMeter + 15.0
ShowMeter()
DriftLoop()<suspends> : void =
loop:
Sleep(1.0)
# Bleed the raw meter down over time.
set RawMeter = RawMeter - 4.0
ShowMeter()
ShowMeter() : void =
# Clamp guarantees the shown value is always in [0, 100],
# no matter how far RawMeter has drifted.
Shown := Clamp(RawMeter, MeterMin, MeterMax)
MeterHud.SetText(treasure_text("Treasure: {Round[Shown]}%"))
Line by line:
treasure_text<localizes>turns a plain string into amessage, whichSetTextrequires. There is noStringToMessage.CrankPlateandMeterHudare@editabledevice fields — you assign real placed devices in the UEFN details panel.RawMeteris avarbecause it changes. It's allowed to go negative or above 100; that's fine because we never show it directly.- In
OnCrank, thetrigger_device'sTriggeredEventhands us(Agent : ?agent). We don't even need the agent here, so we just add progress. DriftLoopruns forever in aspawn, subtracting a little each second so an idle meter falls back toward empty.ShowMeteris the star:Clamp(RawMeter, MeterMin, MeterMax)returnsRawMetersqueezed into[0.0, 100.0]. Crank past 100 and it shows 100; drift below 0 and it shows 0.Round[Shown]converts the clamped float to a clean integer for display.
Common patterns
Capping collected doubloons with Min
A chest can only hold so much gold. When a player deposits coins, use Min so the stored amount never exceeds the chest's capacity — and grant the difference back later if you like.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
doubloon_text<localizes>(S : string) : message = "{S}"
treasure_chest := class(creative_device):
@editable
DepositButton : button_device = button_device{}
@editable
ChestHud : hud_message_device = hud_message_device{}
var Stored : int = 0
Capacity : int = 50
OnBegin<override>()<suspends>:void =
DepositButton.InteractedWithEvent.Subscribe(OnDeposit)
OnDeposit(Agent : agent) : void =
# Player tries to add 12 coins, but the chest is capped.
Wanted := Stored + 12
# Min keeps us at or below Capacity.
set Stored = Min(Wanted, Capacity)
ChestHud.SetText(doubloon_text("Gold: {Stored}/{Capacity}"))
Min(Wanted, Capacity) returns whichever is smaller, so Stored can never pass 50. Note button_device's InteractedWithEvent hands the agent directly (not an option).
Enforcing a floor with Max
When a shark bites, the crew loses morale — but morale should never go below zero. Max gives you a clean "never below" floor.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
morale_text<localizes>(S : string) : message = "{S}"
crew_morale := class(creative_device):
@editable
SharkTrigger : trigger_device = trigger_device{}
@editable
MoraleHud : hud_message_device = hud_message_device{}
var Morale : int = 100
OnBegin<override>()<suspends>:void =
SharkTrigger.TriggeredEvent.Subscribe(OnBite)
OnBite(Agent : ?agent) : void =
# Lose 30 morale, but Max clamps the floor to 0.
set Morale = Max(Morale - 30, 0)
MoraleHud.SetText(morale_text("Crew Morale: {Morale}"))
Max(Morale - 30, 0) returns 0 whenever the subtraction would go negative, so morale bottoms out gracefully.
Clamping a cannon's aim angle
A cannon should only tilt between 0° and 60°. Whatever raw angle you compute from player input, Clamp keeps the barrel from pointing at the sea floor or straight up.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
aim_text<localizes>(S : string) : message = "{S}"
pirate_cannon := class(creative_device):
@editable
RaiseButton : button_device = button_device{}
@editable
AimHud : hud_message_device = hud_message_device{}
var AimAngle : float = 0.0
MinAngle : float = 0.0
MaxAngle : float = 60.0
OnBegin<override>()<suspends>:void =
RaiseButton.InteractedWithEvent.Subscribe(OnRaise)
OnRaise(Agent : agent) : void =
# Each press nudges the barrel up 25 degrees...
Raw := AimAngle + 25.0
# ...but Clamp keeps it between 0 and 60.
set AimAngle = Clamp(Raw, MinAngle, MaxAngle)
AimHud.SetText(aim_text("Cannon Aim: {Round[AimAngle]} deg"))
After three presses the raw angle would be 75°, but Clamp pins it to 60° — the barrel stops at its physical limit.
Gotchas
Clampis float-only;Min/Maxshown here are int. Verse does not auto-convert int↔float.Clamp(RawMeter, 0.0, 100.0)needs float literals (0.0, not0). For integers useMin/Max— or convert withRound[...],Floor[...], orInt[...].messageparams never take raw strings.SetTextwants amessage. Declare a<localizes>helper liketreasure_text<localizes>(S:string):message = "{S}"and passtreasure_text("..."). There is noStringToMessage.- Argument order doesn't break
Clamp. The docs note it "robustly handles different argument orderings" —Clamp(V, 100.0, 0.0)still constrains to the 0–100 range. But write bounds low-then-high for readability. - Clamp the displayed value, not necessarily the stored one. In the walkthrough
RawMeteris free to drift out of range; we only clamp when showing. This keeps the underlying math simple and avoids sticky values pinned at a boundary. - Call devices from
@editablefields. The math functions are global built-ins, but the HUD/trigger/button you drive with the result MUST be@editablefields on yourcreative_device, subscribed inOnBegin. A bareSomeDevice.Method()on an undeclared device fails with 'Unknown identifier'. trigger_devicegives you?agent;button_devicegives youagent. Match your handler signature to the event. If you get an option, unwrap withif (A := Agent?):before using it.