Reference Devices compiles

pinball_flipper_device: Physics-Powered Knockback Flippers

The `pinball_flipper_device` is a physics prop that rotates counterclockwise when triggered, knocking players away and upward — perfect for pinball arenas, obstacle courses, and trap rooms. From Verse you can enable or disable flippers on demand, force-activate them against a specific agent, and listen for every hit to award score or trigger follow-up logic. This article covers all three API entry points with real, compilable examples.

Updated Examples verified on the live UEFN compiler
Watch the Knotpinball_flipper_device in ~90 seconds.

Overview

The pinball_flipper_device solves a very specific game problem: you need a physical surface that launches players. By default any player who walks into the flipper's front face triggers it — the flipper rotates counterclockwise and sends the player flying. In Verse you get three levers:

Need API
Turn the flipper on/off (e.g. only active during a wave) Enable() / Disable()
Force-fire the flipper at a specific player from code Activate(Agent)
React every time a player gets hit ActivatedEvent

Typical use-cases include:

  • Pinball arenas — multiple flippers that players must dodge or ride.
  • Trap corridors — flippers that are hidden until a pressure plate is stepped on.
  • Score multipliers — award bonus points every time a player survives a flipper hit.
  • Timed gauntlets — flippers that cycle on/off in waves.

API Reference

pinball_flipper_device

Used to move, damage, and give scores to players that interact with it. By default, it is activated by any player touching its front face, which rotates it counterclockwise and knocks those players away from it and slightly upward.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).

pinball_flipper_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>(Agent:agent):void Causes Agent to activate this device.

Walkthrough

Scenario: The Trap Corridor

A player steps on a trigger_device pressure plate. Three pinball_flipper_devices that were previously disabled suddenly enable. Whenever a flipper hits a player, a score manager awards bonus points. When the round ends (a second trigger fires) the flippers disable again.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }

# Localized helper — needed any time a method expects a `message` param.
# (pinball_flipper_device has no message params, so this is here as a reminder
# pattern; remove if unused in your own project.)

trap_corridor_manager := class(creative_device):

    # ── Editable references ─────────────────────────────────────────────
    # Wire these to your placed devices in the UEFN Details panel.

    @editable
    ActivatePlate : trigger_device = trigger_device{}

    @editable
    DeactivatePlate : trigger_device = trigger_device{}

    @editable
    Flipper1 : pinball_flipper_device = pinball_flipper_device{}

    @editable
    Flipper2 : pinball_flipper_device = pinball_flipper_device{}

    @editable
    Flipper3 : pinball_flipper_device = pinball_flipper_device{}

    @editable
    ScoreManager : score_manager_device = score_manager_device{}

    # ── Lifecycle ────────────────────────────────────────────────────────

    OnBegin<override>()<suspends> : void =
        # Start with all flippers disabled — players can walk through safely.
        Flipper1.Disable()
        Flipper2.Disable()
        Flipper3.Disable()

        # Subscribe to the pressure plates.
        ActivatePlate.TriggeredEvent.Subscribe(OnActivatePlateTriggered)
        DeactivatePlate.TriggeredEvent.Subscribe(OnDeactivatePlateTriggered)

        # Subscribe to each flipper's activation event to award score.
        Flipper1.ActivatedEvent.Subscribe(OnFlipperHit)
        Flipper2.ActivatedEvent.Subscribe(OnFlipperHit)
        Flipper3.ActivatedEvent.Subscribe(OnFlipperHit)

    # ── Event handlers ───────────────────────────────────────────────────

    # Called when a player steps on the "arm the trap" plate.
    # trigger_device sends ?agent, so we unwrap it before use.
    OnActivatePlateTriggered(TriggeringAgent : ?agent) : void =
        Flipper1.Enable()
        Flipper2.Enable()
        Flipper3.Enable()

    # Called when a player steps on the "disarm" plate.
    OnDeactivatePlateTriggered(TriggeringAgent : ?agent) : void =
        Flipper1.Disable()
        Flipper2.Disable()
        Flipper3.Disable()

    # ActivatedEvent sends a plain `agent` (not optional).
    # Award score to whoever survived the hit.
    OnFlipperHit(HitAgent : agent) : void =
        ScoreManager.AddScore(HitAgent, 50)

Line-by-line explanation

Lines What's happening
@editable fields Declare every device as an editable field so UEFN can wire the placed instances. A bare Flipper1.Enable() without this declaration fails with Unknown identifier.
Flipper1.Disable() × 3 Called immediately in OnBegin — the corridor is safe at round start.
ActivatePlate.TriggeredEvent.Subscribe(...) trigger_device.TriggeredEvent sends ?agent; the handler signature must match (TriggeringAgent : ?agent).
Flipper1.ActivatedEvent.Subscribe(OnFlipperHit) ActivatedEvent is listenable(agent) — it sends a plain (non-optional) agent, so the handler takes (HitAgent : agent).
ScoreManager.AddScore(HitAgent, 50) Rewards the player who survived the flipper. Swap for any follow-up logic you need.

Common patterns

Pattern 1 — Force-activate a flipper on a specific player

Use Activate(Agent) to programmatically fire the flipper at a player — useful for a boss encounter where the boss "slaps" a player with a flipper on command.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }

boss_slap_device := class(creative_device):

    # The flipper that acts as the boss's "hand".
    @editable
    BossFlipper : pinball_flipper_device = pinball_flipper_device{}

    # A trigger the boss AI (or a button) fires to slap the nearest player.
    @editable
    SlapTrigger : trigger_device = trigger_device{}

    OnBegin<override>()<suspends> : void =
        SlapTrigger.TriggeredEvent.Subscribe(OnSlapTriggered)

    # trigger_device sends ?agent — unwrap to get the real agent.
    OnSlapTriggered(MaybeAgent : ?agent) : void =
        if (A := MaybeAgent?):
            # Force the flipper to activate AS IF this agent touched it.
            BossFlipper.Activate(A)

Key point: Activate(Agent) fires the flipper's full physics response — the rotation, the knockback, and the ActivatedEvent — exactly as if the agent walked into it naturally.


Pattern 2 — Timed wave: flippers cycle on/off every few seconds

Demonstrates Enable and Disable in a loop, covering the on/off lifecycle without any player input.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }

flipper_wave_controller := class(creative_device):

    @editable
    WaveFlipper : pinball_flipper_device = pinball_flipper_device{}

    # How long (seconds) each state lasts.
    @editable
    OnDuration : float = 3.0

    @editable
    OffDuration : float = 2.0

    OnBegin<override>()<suspends> : void =
        # Cycle forever for the duration of the round.
        loop:
            WaveFlipper.Enable()
            Sleep(OnDuration)
            WaveFlipper.Disable()
            Sleep(OffDuration)

Why loop works here: OnBegin is a suspending context, so Sleep yields without blocking other game logic. The flipper pulses on/off for the entire match.


Pattern 3 — Track total hits across all flippers and end the round

Subscribes to ActivatedEvent on multiple flippers and ends the game after a target hit count, showing event aggregation.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Native }

flipper_hit_counter := class(creative_device):

    @editable
    FlipperA : pinball_flipper_device = pinball_flipper_device{}

    @editable
    FlipperB : pinball_flipper_device = pinball_flipper_device{}

    @editable
    EndGameDevice : end_game_device = end_game_device{}

    # Mutable hit counter.
    var HitCount : int = 0

    # End the round after this many total flipper hits.
    @editable
    HitTarget : int = 10

    OnBegin<override>()<suspends> : void =
        FlipperA.ActivatedEvent.Subscribe(OnAnyFlipperHit)
        FlipperB.ActivatedEvent.Subscribe(OnAnyFlipperHit)

    OnAnyFlipperHit(HitAgent : agent) : void =
        set HitCount = HitCount + 1
        if (HitCount >= HitTarget):
            EndGameDevice.Activate(HitAgent)

set keyword: Verse requires set to mutate a var field — writing HitCount = HitCount + 1 without set is a compile error.


Gotchas

1. @editable is non-negotiable

Every pinball_flipper_device (and any other placed device) must be declared as an @editable field inside your creative_device class. Referencing a device by name without this annotation causes an Unknown identifier compile error — the Verse runtime has no way to find the placed instance.

2. ActivatedEvent sends agent, not ?agent

ActivatedEvent : listenable(agent) — the handler signature is (HitAgent : agent), not (HitAgent : ?agent). Contrast this with trigger_device.TriggeredEvent which sends ?agent and requires an if (A := MaybeAgent?): unwrap. Getting these mixed up causes a type-mismatch compile error.

3. Activate(Agent) requires a valid agent

Activate takes a plain agent — if you're calling it from a trigger_device handler you must unwrap the ?agent first (see Pattern 1). Passing an optional directly is a type error.

4. Disable does not reset mid-swing

If a flipper is mid-rotation when you call Disable(), the physics for that swing still completes. Disable prevents future activations; it does not freeze an in-progress rotation.

5. No message params on this device

pinball_flipper_device has no methods that accept message. If you add a billboard_device or similar alongside it and need localized text, remember: Verse has no StringToMessage function. Declare a helper like MyText<localizes>(S:string):message = "{S}" and pass MyText("...") instead of a raw string.

6. Sleep requires a float, not an int

When using Sleep with an editable duration field, declare it as float (e.g. OnDuration : float = 3.0). Verse does not auto-convert int to floatSleep(3) is a compile error; Sleep(3.0) is correct.

Device Settings & Options

The pinball_flipper_device User Options panel in the UEFN editor — every setting you can tune.

Pinball Flipper Device settings and options panel in the UEFN editor — Flip Direction, On Triggered Knockback, On Bump Knockback, Fall Damage, Reset Time, Flipper Color, Knockup Amount, Score Value
Pinball Flipper Device — User Options in the UEFN editor: Flip Direction, On Triggered Knockback, On Bump Knockback, Fall Damage, Reset Time, Flipper Color, Knockup Amount, Score Value
⚙️ Settings on this device (8)

Setting names read from the panel above — may be partial; the screenshots are the source of truth.

Flip Direction
On Triggered Knockback
On Bump Knockback
Fall Damage
Reset Time
Flipper Color
Knockup Amount
Score Value

Build your own lesson with pinball_flipper_device

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →