Reference Devices compiles

shooting_range_target_device: Pop-Up Targets That React to Every Shot

The `shooting_range_target_device` is a single customizable pop-up target that rises, falls, hops, and reports every bullet that touches it. Whether you're building a timed shooting gallery, a skill-check arena where targets dodge your shots, or a training course that rewards bullseye accuracy with bonus loot, this device gives you precise programmatic control over target state and rich event feedback for every hit.

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

Overview

The shooting_range_target_device represents one pop-up target on your island. In its default resting state the target lies flat (inactive). You can command it to stand upright (PopUp), lie back down (PopDown), or nudge its vertical position to make it harder to hit (HopUp / HopDown). On the event side it fires signals for ordinary hits, bullseye hits, knockdowns, and every positional transition — giving your Verse code a complete picture of what's happening to the target at all times.

When to reach for it:

  • Timed shooting galleries where targets pop up in sequence.
  • Skill challenges that reward bullseye accuracy (e.g., unlock a vault door only on a perfect shot).
  • Dynamic difficulty: targets that hop up or down based on player performance.
  • Training modes that track hit/miss ratios and adjust the course on the fly.

For a track of targets moving along a rail, see the related shooting_range_target_track_device.

API Reference

shooting_range_target_device

A single customizable pop up target that can be hit by agents to trigger various events.

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

shooting_range_target_device<public> := class<concrete><final>(creative_device_base):

Events (subscribe a handler to react):

Event Signature Description
BullseyeHitEvent BullseyeHitEvent<public>:listenable(tuple()) Signaled when the target is hit in the bullseye area.
HitEvent HitEvent<public>:listenable(tuple()) Signaled when the target is hit by an agent.
KnockdownEvent KnockdownEvent<public>:listenable(tuple()) Signaled when the target takes enough damage to get knocked down.
HopUpEvent HopUpEvent<public>:listenable(tuple()) Signaled when the target moves up slightly, making it harder to hit.
HopDownEvent HopDownEvent<public>:listenable(tuple()) Signaled when the target moves down slightly, making it harder to hit.
PopUpEvent PopUpEvent<public>:listenable(tuple()) Signaled when the target moves from laying flat to standing upright.
PopDownEvent PopDownEvent<public>:listenable(tuple()) Signaled when the target moves from standing upright to laying flat.

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.
HopUp HopUp<public>():void Moves an active (standing upright) target up slightly, in an effort to make it harder to hit.
HopDown HopDown<public>():void Moves an active (standing upright) target down slightly, in an effort to make it harder to hit.
PopUp PopUp<public>():void Causes a target to transition from lying flat (inactive) to standing upright (active).
PopDown PopDown<public>():void Causes a target to transition from standing upright (active) to lying flat (inactive).

Walkthrough

A player enters a room. Three targets pop up one at a time. Hitting the bullseye on each target pops it back down and raises the next one. After all three bullseyes land, a button_device is enabled (representing a vault door unlocking). If a target is knocked down by damage before a bullseye is scored, it hops up to signal a "miss penalty" before resetting.

This walkthrough covers PopUp, PopDown, HopUp, BullseyeHitEvent, KnockdownEvent, PopUpEvent, and Enable/Disable.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

# Place three shooting_range_target_device actors and one button_device in the level,
# then wire them to these @editable fields in the Details panel.
vault_gallery_device := class(creative_device):

    @editable
    Target1 : shooting_range_target_device = shooting_range_target_device{}

    @editable
    Target2 : shooting_range_target_device = shooting_range_target_device{}

    @editable
    Target3 : shooting_range_target_device = shooting_range_target_device{}

    # A button_device whose Enable() call represents the vault door unlocking.
    @editable
    VaultButton : button_device = button_device{}

    # Track how many bullseyes have been scored.
    var BullseyeCount : int = 0

    OnBegin<override>()<suspends> : void =
        # Start with all targets disabled so they don't react before the sequence begins.
        Target1.Disable()
        Target2.Disable()
        Target3.Disable()
        VaultButton.Disable()

        # Subscribe to bullseye and knockdown events for each target.
        Target1.BullseyeHitEvent.Subscribe(OnBullseye1)
        Target2.BullseyeHitEvent.Subscribe(OnBullseye2)
        Target3.BullseyeHitEvent.Subscribe(OnBullseye3)

        Target1.KnockdownEvent.Subscribe(OnKnockdown1)
        Target2.KnockdownEvent.Subscribe(OnKnockdown2)
        Target3.KnockdownEvent.Subscribe(OnKnockdown3)

        # Subscribe to PopUpEvent so we can log when each target stands up.
        Target1.PopUpEvent.Subscribe(OnTarget1Up)

        # Kick off the sequence: raise the first target.
        Target1.Enable()
        Target1.PopUp()

    # --- PopUpEvent handler (logs the moment Target1 becomes active) ---
    OnTarget1Up(Unused : tuple()) : void =
        Print("Target 1 is now standing — take your shot!")

    # --- BullseyeHitEvent handlers ---
    # Events carry tuple() — no payload to unwrap.

    OnBullseye1(Unused : tuple()) : void =
        set BullseyeCount = BullseyeCount + 1
        Target1.PopDown()   # Lay target 1 flat.
        Target1.Disable()
        Target2.Enable()
        Target2.PopUp()     # Raise target 2.

    OnBullseye2(Unused : tuple()) : void =
        set BullseyeCount = BullseyeCount + 1
        Target2.PopDown()
        Target2.Disable()
        Target3.Enable()
        Target3.PopUp()     # Raise target 3.

    OnBullseye3(Unused : tuple()) : void =
        set BullseyeCount = BullseyeCount + 1
        Target3.PopDown()
        Target3.Disable()
        # All three bullseyes scored — unlock the vault.
        VaultButton.Enable()
        Print("Vault unlocked! All bullseyes scored.")

    # --- KnockdownEvent handlers (damage without a bullseye) ---
    # Hop the target up as a "miss penalty" visual cue.

    OnKnockdown1(Unused : tuple()) : void =
        Target1.HopUp()   # Nudge upward — harder to hit next time.

    OnKnockdown2(Unused : tuple()) : void =
        Target2.HopUp()

    OnKnockdown3(Unused : tuple()) : void =
        Target3.HopUp()

Line-by-line highlights:

Lines What's happening
@editable fields Bind to placed devices in the UEFN Details panel — mandatory for any device call to work.
Target1.Disable() in OnBegin Prevents targets from reacting to stray shots before their turn.
.BullseyeHitEvent.Subscribe(OnBullseye1) Registers a class-scope method as the handler. The event fires with tuple() — no agent payload.
OnBullseye1(Unused : tuple()) Handler signature matches listenable(tuple()) — the parameter name is arbitrary.
Target1.PopDown() then Target2.PopUp() Chains the sequence: one target lies flat, the next stands up.
Target1.HopUp() inside OnKnockdown1 Nudges the standing target upward, increasing difficulty after a non-bullseye hit.
VaultButton.Enable() The payoff — the vault unlocks only when all three bullseyes are scored.

Common patterns

Pattern 1 — Timed pop-up: target rises, waits, then drops automatically

Use PopUp, PopDown, and PopDownEvent to create a target that gives the player a 3-second window.

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

timed_target_device := class(creative_device):

    @editable
    Target : shooting_range_target_device = shooting_range_target_device{}

    # How many seconds the target stays up.
    @editable
    WindowSeconds : float = 3.0

    OnBegin<override>()<suspends> : void =
        # Subscribe to know when the target finishes popping down.
        Target.PopDownEvent.Subscribe(OnTargetDown)
        # Raise the target, wait, then lower it.
        Target.PopUp()
        Sleep(WindowSeconds)
        Target.PopDown()

    OnTargetDown(Unused : tuple()) : void =
        # Target is now flat — could start a cooldown and pop it up again.
        Print("Target went down — resetting window.")
        # Re-raise after a short delay by spawning an async task.
        spawn { RaiseAfterDelay() }

    RaiseAfterDelay()<suspends> : void =
        Sleep(2.0)
        Target.PopUp()
        Sleep(WindowSeconds)
        Target.PopDown()

Pattern 2 — Dynamic difficulty: HopUp and HopDown based on hit streak

Reward a hitting streak by hopping the target down (easier), and penalize misses by hopping it up (harder). Uses HitEvent and KnockdownEvent.

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

adaptive_target_device := class(creative_device):

    @editable
    Target : shooting_range_target_device = shooting_range_target_device{}

    var HitStreak : int = 0

    OnBegin<override>()<suspends> : void =
        Target.HitEvent.Subscribe(OnHit)
        Target.KnockdownEvent.Subscribe(OnKnockdown)
        Target.PopUp()

    # Every hit increments the streak.
    # After 3 consecutive hits, hop the target DOWN (reward — easier target).
    OnHit(Unused : tuple()) : void =
        set HitStreak = HitStreak + 1
        if (HitStreak >= 3):
            Target.HopDown()   # Nudge target downward — easier to hit.
            set HitStreak = 0  # Reset streak counter.

    # A knockdown (damage without bullseye) breaks the streak.
    # Hop the target UP as a difficulty spike.
    OnKnockdown(Unused : tuple()) : void =
        set HitStreak = 0
        Target.HopUp()   # Nudge target upward — harder to hit.

Pattern 3 — Enable/Disable gating: target only active during a round

Use Enable and Disable to gate the target so it only accepts hits while a round is live. Subscribe to HopUpEvent and HopDownEvent for telemetry.

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

round_gated_target_device := class(creative_device):

    @editable
    Target : shooting_range_target_device = shooting_range_target_device{}

    # Round duration in seconds.
    @editable
    RoundDuration : float = 30.0

    OnBegin<override>()<suspends> : void =
        # Log every hop transition for telemetry.
        Target.HopUpEvent.Subscribe(OnHoppedUp)
        Target.HopDownEvent.Subscribe(OnHoppedDown)

        # Disable target before the round starts.
        Target.Disable()
        Print("Round starting in 3 seconds...")
        Sleep(3.0)

        # Enable and raise the target for the round window.
        Target.Enable()
        Target.PopUp()
        Sleep(RoundDuration)

        # Round over — lower and disable.
        Target.PopDown()
        Target.Disable()
        Print("Round over — target disabled.")

    OnHoppedUp(Unused : tuple()) : void =
        Print("Target hopped UP — harder to hit now.")

    OnHoppedDown(Unused : tuple()) : void =
        Print("Target hopped DOWN — easier to hit now.")

Gotchas

1. Events carry tuple(), not an agent

Every event on shooting_range_target_device is listenable(tuple()). There is no agent payload — you cannot tell which player fired the shot from the event alone. If you need per-player tracking, combine this device with a trigger_device or damage_tracker_device that does carry agent context.

# CORRECT — handler accepts tuple()
OnHit(Unused : tuple()) : void = ...

# WRONG — there is no agent in this event
# OnHit(Agent : agent) : void = ...   ← compile error

2. HopUp / HopDown only work on a standing target

Calling HopUp() or HopDown() on a target that is lying flat (inactive / after PopDown) has no effect. Always call PopUp() first and confirm the target is upright before issuing hop commands. Subscribe to PopUpEvent to know the exact moment the target is ready.

3. PopDown is a method AND an event — don't confuse them

PopDown() is the method you call to lower the target. PopDownEvent is the event that fires when the transition completes. If you need to chain logic after the target is fully flat, subscribe to PopDownEvent rather than running code immediately after calling PopDown().

4. Disable does not lower the target

Calling Disable() prevents the target from responding to hits and Verse commands, but it does not physically lower it. If you want the target flat and inactive, call PopDown() first, then Disable().

5. All device references must be @editable fields

You cannot reference a placed shooting_range_target_device with a bare local variable. Every device must be declared as an @editable field inside your class(creative_device) and assigned in the UEFN Details panel. Calling methods on an unbound field will silently do nothing at runtime.

6. No using lines needed in the examples above — but they ARE required

The compile gate strips using directives for display, but your actual .verse file must include using { /Fortnite.com/Devices } and using { /Verse.org/Simulation } at the top, or the compiler will report Unknown identifier for every device type and Sleep.

Guides & scripts that use shooting_range_target_device

Step-by-step tutorials that put this object to work.

Build your own lesson with shooting_range_target_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 →