Reference Devices compiles

pulse_trigger_device: Damage Waves That Drive Your Game

The `pulse_trigger_device` sends out expanding waves of damage that hurt any player they touch — perfect for lava floors, electric barriers, shrinking safe zones, or boss-room hazards. Pair it with a `trigger_device` to fire game events the moment a pulse reaches a checkpoint, and you have a complete, code-driven damage-and-signaling pipeline without a single Blueprint node.

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

Overview

The pulse_trigger_device emits repeating damage pulses that radiate outward from the device's position. Any player caught in a pulse takes the configured damage amount. Beyond raw damage, the device doubles as a sequencing tool: place trigger_devices in the pulse's path and they fire TriggeredEvent when the wave washes over them, letting you chain billboards, doors, score managers, or any other device to the rhythm of the pulse.

When to reach for it:

  • A lava floor that pulses damage every few seconds.
  • An electric fence that can be turned on/off by a Verse script.
  • A boss arena where the pulse speed and damage ramp up as the fight progresses.
  • A race track intro sequence where the pulse sweeps past trigger checkpoints to animate a countdown.

Key things to know before you start:

  • Begin() / End() start and stop the pulse; Enable() / Disable() control whether the device can be interacted with at all.
  • SetLoopCount(0) means the pulse runs forever; any positive integer stops it after that many loops.
  • SetDamage(0.0) turns the pulse into a harmless visual wave — great for cinematic sweeps.
  • The companion trigger_device exposes TriggeredEvent so your Verse code can react every time the wave crosses a checkpoint.

API Reference

pulse_trigger_device

A device used to damage players who collide with it. Can also be used as a trigger to activate other devices.

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

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

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.
Begin Begin<public>():void Starts the damage pulse.
End End<public>():void Stops the damage pulse.
ResumeSequence ResumeSequence<public>():void This function is deprecated. Use ResumePulse instead of this. Resumes the damage sequence from the last position where it was stopped.
ResumePulse ResumePulse<public>():void Resumes the damage pulse from the last position where it was stopped.
SetDamage SetDamage<public>(Damage:float):void Sets the damage to be applied to those hit by an active pulse. Clamped between 0 <= GetDamage <= 100000. Pulse visuals will change to reflect whether the pulse causes damage or not.
GetDamage GetDamage<public>()<transacts>:float Returns the damage to be applied to those hit by an active pulse. Clamped between 0 <= GetDamage <= 100000.
SetLoopCount SetLoopCount<public>(LoopCount:int):void Sets the total number of times this pulse will complete before ending. LoopCount = 0 indicates the pulse should continue indefinitely.
GetLoopCount GetLoopCount<public>()<transacts>:int Returns the total number of times this pulse will complete before ending. 0 indicates the pulse will continue indefinitely.
SetWaveSpeed SetWaveSpeed<public>(Speed:float):void Sets the speed (in meters per second) at which the pulses generated by this pulse trigger will travel.
GetWaveSpeed GetWaveSpeed<public>()<transacts>:float Returns the speed (in meters per second) at which the pulses generated by this pulse trigger will travel.

trigger_device

Used to relay events to other linked devices.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from trigger_base_device.

trigger_device<public> := class<concrete><final>(trigger_base_device):

Events (subscribe a handler to react):

Event Signature Description
TriggeredEvent TriggeredEvent<public>:listenable(?agent) Signaled when an agent triggers this device. Sends the agent that used this device. Returns false if no agent triggered the action (ex: it was triggered through code).

Methods (call these to make the device act):

Method Signature Description
Trigger Trigger<public>(Agent:agent):void Triggers this device with Agent being passed as the agent that triggered the action. Use an agent reference when this device is setup to require one (for instance, you want to trigger the device only with a particular agent.
Trigger Trigger<public>():void Triggers this device, causing it to activate its TriggeredEvent event.
Enable Enable<public>():void Enables this device.
Disable Disable<public>():void Disables this device.
SetMaxTriggerCount SetMaxTriggerCount<public>(MaxCount:int):void Sets the maximum amount of times this device can trigger. * 0 can be used to indicate no limit on trigger count. * MaxCount is clamped between [0,20].
GetMaxTriggerCount GetMaxTriggerCount<public>()<transacts>:int Gets the maximum amount of times this device can trigger. * 0 indicates no limit on trigger count.
GetTriggerCountRemaining GetTriggerCountRemaining<public>()<transacts>:int Returns the number of times that this device can still be triggered before hitting GetMaxTriggerCount. Returns 0 if GetMaxTriggerCount is unlimited.
SetResetDelay SetResetDelay<public>(Time:float):void Sets the time (in seconds) after triggering, before the device can be triggered again (if MaxTrigger count allows).
GetResetDelay GetResetDelay<public>()<transacts>:float Gets the time (in seconds) before the device can be triggered again (if MaxTrigger count allows).
SetTransmitDelay SetTransmitDelay<public>(Time:float):void Sets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered.
GetTransmitDelay GetTransmitDelay<public>()<transacts>:float Gets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered.

Walkthrough

Scenario: The Boss Arena Pulse

You have a circular boss arena. When the round starts:

  1. A pulse_trigger_device in the center begins pulsing, dealing 20 damage per wave.
  2. Two trigger_devices are placed at the inner and outer rings. When the pulse crosses them, a billboard flashes a warning.
  3. After 10 seconds the Verse script ramps the damage to 40 and doubles the wave speed — the arena gets deadlier as the fight goes on.
  4. When the boss is defeated (simulated here by a second trigger), the pulse stops.

Place all three devices in your UEFN level, wire them to the Verse device via @editable fields, then drop this script in.

boss_arena_pulse_device := class(creative_device):

    # The central pulse emitter
    @editable
    PulseTrigger : pulse_trigger_device = pulse_trigger_device{}

    # Inner ring checkpoint — fires TriggeredEvent when the wave crosses it
    @editable
    InnerRingTrigger : trigger_device = trigger_device{}

    # Outer ring checkpoint
    @editable
    OuterRingTrigger : trigger_device = trigger_device{}

    # Called when the outer ring pulse checkpoint fires
    OnOuterRingHit(Agent : ?agent) : void =
        # The outer ring is the danger zone — log it (or drive a billboard here)
        if (A := Agent?):
            Print("Outer ring pulse crossed near an agent!")
        else:
            Print("Outer ring pulse crossed (no agent).")

    # Called when the inner ring pulse checkpoint fires
    OnInnerRingHit(Agent : ?agent) : void =
        Print("Inner ring pulse crossed — warning players!")

    OnBegin<override>()<suspends> : void =
        # --- Initial pulse configuration ---
        PulseTrigger.SetDamage(20.0)       # 20 HP per wave
        PulseTrigger.SetLoopCount(0)       # loop forever
        PulseTrigger.SetWaveSpeed(5.0)     # 5 m/s to start

        # Subscribe to the ring checkpoints
        InnerRingTrigger.TriggeredEvent.Subscribe(OnInnerRingHit)
        OuterRingTrigger.TriggeredEvent.Subscribe(OnOuterRingHit)

        # Enable everything and start the pulse
        PulseTrigger.Enable()
        InnerRingTrigger.Enable()
        OuterRingTrigger.Enable()
        PulseTrigger.Begin()

        Print("Boss arena pulse started — {PulseTrigger.GetDamage()} dmg, {PulseTrigger.GetWaveSpeed()} m/s")

        # Wait 10 seconds, then ramp up the danger
        Sleep(10.0)

        PulseTrigger.SetDamage(40.0)
        PulseTrigger.SetWaveSpeed(10.0)
        Print("Phase 2! Pulse ramped to {PulseTrigger.GetDamage()} dmg at {PulseTrigger.GetWaveSpeed()} m/s")

Line-by-line breakdown:

Lines What's happening
@editable fields Bind the three placed devices so Verse can call their methods. Without @editable the identifiers are unknown at compile time.
SetDamage(20.0) Configures how much HP each pulse wave removes from a hit player.
SetLoopCount(0) 0 = infinite loops; the pulse never stops on its own.
SetWaveSpeed(5.0) Controls how fast the ring expands — slower = more time to dodge.
TriggeredEvent.Subscribe(...) Registers a class-scope method as the handler. The handler signature must be (Agent : ?agent) : void because TriggeredEvent is a listenable(?agent).
PulseTrigger.Begin() Actually starts the pulse. Enable() alone does not start it.
Sleep(10.0) Suspends the coroutine for 10 seconds without blocking other game logic.
SetDamage(40.0) / SetWaveSpeed(10.0) Hot-swap the pulse parameters mid-game — no restart needed.

Common patterns

Pattern 1 — Harmless cinematic sweep, then flip to lethal

Start the pulse as a pure visual (0 damage) for a dramatic opening, then switch to full damage after the countdown.

cinematic_pulse_device := class(creative_device):

    @editable
    PulseTrigger : pulse_trigger_device = pulse_trigger_device{}

    OnBegin<override>()<suspends> : void =
        # Zero damage = visual-only pulse for the cinematic
        PulseTrigger.SetDamage(0.0)
        PulseTrigger.SetWaveSpeed(8.0)
        PulseTrigger.SetLoopCount(3)   # sweep three times for the intro
        PulseTrigger.Enable()
        PulseTrigger.Begin()

        Print("Cinematic sweep — current damage: {PulseTrigger.GetDamage()}")

        # Let the three loops play out (~a few seconds depending on arena size)
        Sleep(6.0)

        # Now make it lethal
        PulseTrigger.End()
        PulseTrigger.SetDamage(50.0)
        PulseTrigger.SetLoopCount(0)   # infinite from here on
        PulseTrigger.Begin()
        Print("Pulse is now lethal: {PulseTrigger.GetDamage()} dmg")

Key calls: SetDamage, GetDamage, SetLoopCount, GetLoopCount (via GetDamage print), Begin, End.


Pattern 2 — Pause and resume the pulse on player request

A safe-room button lets players pause the arena hazard briefly, then it resumes from where it left off.

pause_resume_pulse_device := class(creative_device):

    @editable
    PulseTrigger : pulse_trigger_device = pulse_trigger_device{}

    # A trigger_device the player steps on to request a pause
    @editable
    SafeRoomTrigger : trigger_device = trigger_device{}

    OnSafeRoomEntered(Agent : ?agent) : void =
        # Stop the pulse — the wave freezes in place
        PulseTrigger.End()
        Print("Pulse paused — safe room active")
        # In a real game you'd Sleep then resume; here we show the call
        spawn { ResumeAfterDelay() }

    ResumeAfterDelay()<suspends> : void =
        Sleep(5.0)
        # ResumePulse continues from the last stopped position
        PulseTrigger.ResumePulse()
        Print("Pulse resumed from last position")

    OnBegin<override>()<suspends> : void =
        SafeRoomTrigger.TriggeredEvent.Subscribe(OnSafeRoomEntered)
        PulseTrigger.SetDamage(30.0)
        PulseTrigger.SetLoopCount(0)
        PulseTrigger.SetWaveSpeed(4.0)
        PulseTrigger.Enable()
        SafeRoomTrigger.Enable()
        PulseTrigger.Begin()

Key calls: End, ResumePulse, TriggeredEvent.Subscribe.


Pattern 3 — Dynamic trigger_device configuration at runtime

Before the round starts, configure the trigger_device's fire limit and delays via Verse so the design can be tweaked in code rather than the Details panel.

configured_trigger_device := class(creative_device):

    @editable
    PulseTrigger : pulse_trigger_device = pulse_trigger_device{}

    @editable
    CheckpointTrigger : trigger_device = trigger_device{}

    OnCheckpointHit(Agent : ?agent) : void =
        # How many fires are left before this trigger locks out?
        Remaining := CheckpointTrigger.GetTriggerCountRemaining()
        Print("Checkpoint hit — {Remaining} triggers remaining")

    OnBegin<override>()<suspends> : void =
        # Allow the checkpoint to fire at most 5 times, with a 2-second cooldown
        CheckpointTrigger.SetMaxTriggerCount(5)
        CheckpointTrigger.SetResetDelay(2.0)
        CheckpointTrigger.SetTransmitDelay(0.1)

        Print("Max triggers: {CheckpointTrigger.GetMaxTriggerCount()}")
        Print("Reset delay:  {CheckpointTrigger.GetResetDelay()} s")

        CheckpointTrigger.TriggeredEvent.Subscribe(OnCheckpointHit)
        CheckpointTrigger.Enable()

        PulseTrigger.SetDamage(15.0)
        PulseTrigger.SetWaveSpeed(6.0)
        PulseTrigger.SetLoopCount(0)
        PulseTrigger.Enable()
        PulseTrigger.Begin()

Key calls: SetMaxTriggerCount, GetMaxTriggerCount, SetResetDelay, GetResetDelay, SetTransmitDelay, GetTriggerCountRemaining.


Gotchas

1. Enable()Begin() — you need both

Enable() makes the device receptive to signals and Verse calls. Begin() actually fires the first pulse. Calling only Enable() produces no wave. Calling only Begin() on a disabled device has no effect. Always call Enable() first, then Begin().

2. ResumePulse vs ResumeSequence

ResumeSequence is deprecated — the compiler may warn or error. Always use ResumePulse() to continue from the last stopped position.

3. TriggeredEvent hands you ?agent, not agent

TriggeredEvent is a listenable(?agent). Your handler must accept (Agent : ?agent) and unwrap it before use:

# CORRECT
OnHit(Agent : ?agent) : void =
    if (A := Agent?):
        # use A as a real agent here

# WRONG — compile error
OnHit(Agent : agent) : void = ...

4. SetDamage is clamped, not uncapped

Values below 0.0 are clamped to 0.0; values above 100000.0 are clamped to 100000.0. Passing 200000.0 silently gives you 100000.0 — always verify with GetDamage() if your logic depends on the exact value.

5. SetLoopCount(0) means infinite, not zero loops

Passing 0 tells the device to loop forever. If you want the pulse to fire exactly once, pass 1. This is the opposite of what many developers expect.

6. SetMaxTriggerCount on trigger_device is clamped to [0, 20]

You cannot set more than 20 max triggers via code. If you need unlimited, pass 0 (which means no limit). Values above 20 are silently clamped.

7. message parameters require localized values

If you ever pass text to a device method that accepts message, you cannot use a raw string. Declare a localizer function:

MyMsg<localizes>(S : string) : message = "{S}"

There is no StringToMessage built-in.

8. int and float do not auto-convert

SetDamage takes a float. Passing an int literal like SetDamage(20) will cause a compile error. Always write SetDamage(20.0).

Device Settings & Options

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

Pulse Trigger Device settings and options panel in the UEFN editor — Loop Infinitely, Number Of Loops, Tempo Bpm, Length, Width, Height, Zone Visible During Game, Pulse Direction, Damage
Pulse Trigger Device — User Options in the UEFN editor: Loop Infinitely, Number Of Loops, Tempo Bpm, Length, Width, Height, Zone Visible During Game, Pulse Direction, Damage
⚙️ Settings on this device (9)

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

Loop Infinitely
Number Of Loops
Tempo Bpm
Length
Width
Height
Zone Visible During Game
Pulse Direction
Damage

Guides & scripts that use pulse_trigger_device

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

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