Overview
A pinball_bumper_device is a triggered bumper. By default it activates when a player touches it, knocking them back, optionally damaging them, and optionally awarding points. It's the building block of any pinball-style minigame — but it's just as useful for momentum gauntlets, knockback arenas, or 'don't touch the walls' challenges.
Reach for it when you want a physical reaction to a player making contact, plus a Verse hook to run game logic the moment it fires. From Verse you get four things:
ActivatedEvent— alistenable(agent)that fires when the bumper is hit, handing you theagentwho hit it. This is where you score, count, or react.Enable()/Disable()— turn the whole bumper on or off (knockback, effects, scoring — all of it).Activate()— fire the bumper from code, even if nobody touched it. Great for scripted chain reactions or testing.
Because it's a placed device, you must declare it as an @editable field inside your creative_device class and assign it in the UEFN Details panel before any of these calls will work.
API Reference
pinball_bumper_device
A triggered bumper that can knock players back, damage them, and award points.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
pinball_bumper_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
ActivatedEvent |
ActivatedEvent<public>:listenable(agent) |
Signaled when this device is activated by an agent. Sends the agent that activated this device. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
Activate |
Activate<public>():void |
Activates this device. |
Walkthrough
Let's build a pinball survival round. Three bumpers are scattered in an arena. Each time a player hits any bumper we award a point through a score_manager_device and count total hits. When the round's hit budget is reached, we Disable() every bumper so the arena goes quiet — and we display a localized callout.
# Pinball survival: bumpers score points, then shut off when the budget runs out.
pinball_arena_device := class(creative_device):
# Drag your three placed bumpers onto these slots in the Details panel.
@editable
BumperA : pinball_bumper_device = pinball_bumper_device{}
@editable
BumperB : pinball_bumper_device = pinball_bumper_device{}
@editable
BumperC : pinball_bumper_device = pinball_bumper_device{}
# A Score Manager handles the actual point granting.
@editable
Scorer : score_manager_device = score_manager_device{}
# How many total bumper hits the round allows before bumpers shut off.
@editable
HitBudget : int = 10
# Running count of how many times any bumper has fired.
var Hits : int = 0
# Localized text helper — message params need this, NOT a raw string.
Callout<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
# Make sure every bumper is live at round start.
BumperA.Enable()
BumperB.Enable()
BumperC.Enable()
# React to a hit on any of the three bumpers with the SAME handler.
BumperA.ActivatedEvent.Subscribe(OnBumperHit)
BumperB.ActivatedEvent.Subscribe(OnBumperHit)
BumperC.ActivatedEvent.Subscribe(OnBumperHit)
# ActivatedEvent hands us the agent who hit the bumper.
OnBumperHit(Hitter : agent) : void =
set Hits = Hits + 1
# Award points to the player who hit it.
Scorer.Activate(Hitter)
# Once the budget is spent, kill all the bumpers.
if (Hits >= HitBudget):
BumperA.Disable()
BumperB.Disable()
BumperC.Disable()
Print("Bumpers offline — hit budget reached.")
Line by line:
- The three
@editablepinball_bumper_devicefields are how Verse reaches your placed bumpers. Without these you can't call any method — a barepinball_bumper_device.Enable()fails with 'Unknown identifier'. Scoreris ascore_manager_device. The bumper itself can award points via its UEFN settings, but routing through a Score Manager from Verse gives us full control of when and to whom.var Hits : int = 0is mutable state we update withset.- In
OnBegin, we callEnable()on each bumper so the round always starts with them active, thenSubscribethe sameOnBumperHitmethod to each bumper'sActivatedEvent. One handler, three sources. OnBumperHit(Hitter : agent)—ActivatedEventislistenable(agent), so the handler receives a non-optionalagentdirectly (no?unwrap needed here).Scorer.Activate(Hitter)grants the configured score to the player who hit the bumper.- When
HitsreachesHitBudget, weDisable()all three bumpers and they stop knocking players or firing events.
Common patterns
Fire a bumper from code (Activate)
Use Activate() to set a bumper off without a player touching it — for a scripted chain reaction or a 'demo' showing players how it works. Here a button triggers the center bumper.
bumper_remote_fire_device := class(creative_device):
@editable
CenterBumper : pinball_bumper_device = pinball_bumper_device{}
@editable
TestButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
CenterBumper.Enable()
# When the button is pressed, fire the bumper from code.
TestButton.InteractedWithEvent.Subscribe(OnButtonPressed)
OnButtonPressed(Agent : agent) : void =
# Activate() sets the bumper off even with no contact.
CenterBumper.Activate()
Temporarily disable a bumper after a hit (Enable/Disable cooldown)
Make a bumper one-shot-then-cool-down: when hit, disable it, wait a few seconds, re-enable. This uses <suspends> with Sleep.
bumper_cooldown_device := class(creative_device):
@editable
Bumper : pinball_bumper_device = pinball_bumper_device{}
@editable
CooldownSeconds : float = 3.0
OnBegin<override>()<suspends> : void =
Bumper.Enable()
Bumper.ActivatedEvent.Subscribe(OnHit)
OnHit(Hitter : agent) : void =
# Kick off the cooldown without blocking the handler.
spawn{ RunCooldown() }
RunCooldown()<suspends> : void =
Bumper.Disable()
Sleep(CooldownSeconds)
Bumper.Enable()
Trigger a cinematic when a bumper is hit
React to ActivatedEvent by playing a sequence — for example, a flashing light show every time the jackpot bumper fires.
bumper_cinematic_device := class(creative_device):
@editable
JackpotBumper : pinball_bumper_device = pinball_bumper_device{}
@editable
LightShow : cinematic_sequence_device = cinematic_sequence_device{}
OnBegin<override>()<suspends> : void =
JackpotBumper.Enable()
JackpotBumper.ActivatedEvent.Subscribe(OnJackpot)
OnJackpot(Hitter : agent) : void =
# Play the light-show sequence for the player who hit it.
LightShow.Play(Hitter)
Gotchas
- You can't call methods on an unassigned device. The
@editablefield gives you a typed handle, but until you drag the actual placed bumper onto that slot in the Details panel, calls do nothing (or the field stays the default empty instance). Always assign in UEFN. ActivatedEventislistenable(agent), notlistenable(?agent). Your handler receives a plainagent— noif (A := Agent?)unwrap is needed. (Compare this totimer_device.SuccessEvent, which is?agentand does need unwrapping.)Disable()stops everything, including the physical knockback and any UEFN-configured score/damage on the device — not just the Verse event. Re-Enable()to bring it back.Activate()takes no agent. Unlikepinball_flipper_device.Activate(Agent)orteleporter_device.Activate(Agent), the bumper'sActivate()is parameterless. Don't pass an agent to it.- Subscribe in
OnBegin, handlers are methods. Event handlers likeOnBumperHitmust be methods at class scope, and you wire them up with.Subscribe(...)insideOnBegin. Subscribing elsewhere or making the handler a local function won't work. messageneeds localization. If you display callouts (e.g. on a billboard or HUD), declare a<localizes>helper likeCallout<localizes>(S:string):message = "{S}"and passCallout("..."). There is noStringToMessage.