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
Scenario: The Vault-Door Shooting Gallery
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.