What you'll learn
- How to spawn and despawn a
powerup_devicefrom Verse instead of relying on editor triggers. - How to grant a buff directly to a player with
Pickup(Agent)and check it withHasEffect. - How to read the live remaining time of a buff with
GetRemainingTime. - How to react the moment any agent picks up the powerup off the ground via
ItemPickedUpEvent.
How it works
powerup_device is the shared abstract base behind Fortnite's collectible buffs — Health Powerup, Damage Amplifier, and friends. Because it's abstract you place a concrete powerup in your level and reference it, but every method below works on all subclasses.
The key surface, resolved from the live digest:
| Member | Signature | Notes |
|---|---|---|
Spawn |
Spawn():void |
Places the powerup into the world so players can grab it. |
Despawn |
Despawn():void |
Removes it from the world. |
IsSpawned |
IsSpawned()<transacts><decides>:void |
Fallible — call inside if/for with []. |
SetDuration |
SetDuration(Time:float):void |
Clamped to the device Min/Max; won't touch already-applied effects. |
GetDuration |
GetDuration()<transacts>:float |
Returns a plain float — call with (). |
Pickup |
Pickup(Agent:agent):void |
Grants the buff directly to that agent. |
GetRemainingTime |
GetRemainingTime(Agent:agent)<transacts>:float |
-1.0 = infinite, 0.0 = agent doesn't have it. |
HasEffect |
HasEffect(Agent:agent)<transacts><decides>:void |
Fallible — use if (Powerup.HasEffect[Agent]):. |
ItemPickedUpEvent |
listenable(agent) |
Fires with the agent who picked it up. |
Watch the effect specifiers: IsSpawned and HasEffect end in <decides>, so you call them with [] inside a failure context. GetRemainingTime and GetDuration return a real float, so you call them with () and read the value — calling them with [] would not compile.
Let's build it
We build a reward-orb objective: stepping on a finish plate spawns the powerup (if needed), stretches its duration, and grants it straight to that player. When anyone picks a powerup up off the ground, we announce who got it and how many seconds of buff remain.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Drives a concrete powerup (Health / Damage Amplifier) from Verse as a reward orb.
reward_orb := class(creative_device):
# A concrete powerup placed in the level (e.g. Health Powerup or Damage Amplifier).
@editable
RewardPowerup : health_powerup_device = health_powerup_device{}
# A trigger standing in for "challenge complete".
@editable
FinishPlate : trigger_device = trigger_device{}
OnBegin<override>()<suspends>: void =
# React whenever a player steps on the finish plate.
FinishPlate.TriggeredEvent.Subscribe(OnFinished)
# React whenever ANY agent scoops the powerup off the ground.
RewardPowerup.ItemPickedUpEvent.Subscribe(OnPickedUp)
# Triggered param is ?agent, so bind it before use.
OnFinished(MaybeAgent : ?agent): void =
if (Agent := MaybeAgent?):
# Make sure the orb is in the world; Spawn is fallible-free but IsSpawned decides.
if (RewardPowerup.IsSpawned[]):
Print("Reward orb already spawned.")
else:
RewardPowerup.Spawn()
# Stretch the buff to 30s (clamped to the device's Min/Max), then read it back.
RewardPowerup.SetDuration(30.0)
Duration := RewardPowerup.GetDuration() # returns float -> use ()
Print("Reward duration set to {Duration}s.")
# Grant the buff straight to the player who finished.
RewardPowerup.Pickup(Agent)
# Confirm the effect actually landed (HasEffect decides -> use []).
if (RewardPowerup.HasEffect[Agent]):
Print("Buff applied directly to finisher.")
# ItemPickedUpEvent sends the agent that picked it up.
OnPickedUp(Agent : agent): void =
# GetRemainingTime returns a float: -1.0 infinite, 0.0 none.
Remaining := RewardPowerup.GetRemainingTime(Agent)
if (Remaining < 0.0):
Print("Player grabbed the orb: infinite duration buff!")
else:
Print("Player grabbed the orb: {Remaining}s of buff remaining.")```
## Try it yourself
- Swap the referenced powerup between a Health Powerup and a Damage Amplifier — the same code drives both because they share the `powerup_device` base.
- Add a second `@editable trigger_device` that calls `RewardPowerup.Despawn()` to pull the orb out of the world when a timer expires.
- In `OnPickedUp`, iterate `GetPlayspace().GetPlayers()` and only announce for players who *don't* already have the effect using `if (not RewardPowerup.HasEffect[OtherAgent]):`.
- Use `SetDuration` with a very large value and confirm the device clamps it to its editor-defined Max via the value returned by `GetDuration()`.
## Recap
You drove a `powerup_device` entirely from Verse: `Spawn`/`IsSpawned` to place it, `SetDuration`/`GetDuration` to control its timer, `Pickup(Agent)` to grant it directly, `HasEffect`/`GetRemainingTime` to inspect a player's buff, and `ItemPickedUpEvent` to react to grabs. The one rule to remember: `<decides>` methods (`IsSpawned`, `HasEffect`) use `[]` inside a failure context, while methods that return a `float` (`GetDuration`, `GetRemainingTime`) use `()` and are read as values.