Reference Devices compiles

npc_spawner_device: Spawning Enemies That React

Need a room full of guards that appear when the player enters, fall back when a boss is killed, or reinforcements that teleport to exact ambush points? The npc_spawner_device is your AI factory. This article shows you its real Verse API — Spawn, SpawnAt, Enable/Disable, DespawnAll, GetAgents, and the SpawnedEvent / EliminatedEvent events — wired into concrete Fortnite scenarios.

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

Overview

The npc_spawner_device spawns NPCs built from a Character Definition asset — guards, monsters, dancing llamas, whatever you configured in the device's Details panel. Unlike the lighter creature/sentry spawners, it gives you full AI: patrol, navigation, and behavior.

Reach for it whenever you want living enemies or allies that the player fights, escorts, or sneaks past — a stronghold of guards, a wave of reinforcements, a single boss at the end of an arena.

In Verse you place the device in your level, then declare an @editable field of type npc_spawner_device and point it at that placed device in the Details panel. From there you can:

  • Spawn an NPC at the device's configured spawn point.
  • SpawnAt an exact world position (e.g. ambush corners).
  • Enable / Disable the device to start/stop automatic spawning.
  • DespawnAll to wipe the room, optionally crediting an eliminator.
  • GetAgents to enumerate everyone this device currently owns.
  • React to SpawnedEvent (someone appeared) and EliminatedEvent (someone died, and who killed them).

API Reference

npc_spawner_device

Used to spawn NPCs made with Character Definition asset.

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

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

Events (subscribe a handler to react):

Event Signature Description
SpawnedEvent SpawnedEvent<public>:listenable(agent) Signaled when a character is spawned. Sends the agent character who was spawned.
EliminatedEvent EliminatedEvent<public>:listenable(device_ai_interaction_result) Signaled when a character is eliminated. Source is the agent that eliminated the character. If the character was eliminated by a non-agent then Source is 'false'. Target is the character that was eliminated.

Methods (call these to make the device act):

Method Signature Description
Enable Enable<public>():void Enables this device. Characters will start to spawn.
Disable Disable<public>():void Disables this device. Characters will despawn if Despawn AIs When Disabled is set.
SetNPCCharacterDefinition SetNPCCharacterDefinition<public>(CharacterDefinition:npc_character_definition)<transacts><decides>:void Set the NPC character definition to use. Fails if the character type is different from one in the current definition.
Spawn Spawn<public>():void Tries to spawn a character.
DespawnAll DespawnAll<public>(Instigator:?agent):void Despawns all characters. If set, Instigator will be considered as the eliminator of those characters.
SpawnAt SpawnAt<public>(Position:(/Verse.org/SpatialMath:)vector3, ?Rotation:?(/Verse.org/SpatialMath:)rotation Spawn a NPC at the given position. When Rotation is not provided, it will default to the Devices rotation. Returns the agent spawned or false if the device has reached its maximum spawn count. This function is <suspends>` because it takes
GetAgents GetAgents<public>()<transacts>:[]agent Get all agents created by this device.

Walkthrough

Scenario: A defense arena. When the round begins we enable a guard spawner and manually spawn the first wave. Every time a guard spawns we count it; every time one is eliminated we count it down, and when the last guard falls we despawn anything remaining and disable the spawner — the room is "cleared."

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

arena_controller := class(creative_device):

    # Point this at the placed NPC Spawner in the Details panel.
    @editable
    GuardSpawner : npc_spawner_device = npc_spawner_device{}

    # How many guards we still expect to spawn this wave.
    var WaveSize : int = 4

    # How many guards are currently alive.
    var AliveCount : int = 0

    OnBegin<override>()<suspends>:void =
        # React when a guard appears or dies.
        GuardSpawner.SpawnedEvent.Subscribe(OnGuardSpawned)
        GuardSpawner.EliminatedEvent.Subscribe(OnGuardEliminated)

        # Turn the device on so its own spawn settings can run...
        GuardSpawner.Enable()

        # ...and kick off the first wave manually.
        for (I := 0..WaveSize - 1):
            GuardSpawner.Spawn()
            Sleep(0.5)  # stagger so they don't all pop in the same frame

    # Handler for SpawnedEvent — receives the agent that spawned.
    OnGuardSpawned(Spawned : agent):void =
        set AliveCount += 1
        Print("Guard spawned. Alive now: {AliveCount}")

    # Handler for EliminatedEvent — receives a device_ai_interaction_result.
    OnGuardEliminated(Result : device_ai_interaction_result):void =
        set AliveCount -= 1
        Print("Guard down. Remaining: {AliveCount}")

        # Who got the kill? Source is an ?agent, so unwrap it.
        if (Killer := Result.Source?):
            Print("Credited to a player.")

        # When the room is empty, clear it out and shut the spawner off.
        if (AliveCount <= 0):
            GuardSpawner.DespawnAll(false)
            GuardSpawner.Disable()
            Print("Arena cleared!")

Line by line:

  • @editable GuardSpawner : npc_spawner_device — the field you bind to the placed device. Without this you cannot call any of its methods (a bare Device.Spawn() fails with Unknown identifier).
  • SpawnedEvent.Subscribe(OnGuardSpawned)SpawnedEvent is listenable(agent), so the handler takes a plain agent (already unwrapped, no ?).
  • EliminatedEvent.Subscribe(OnGuardEliminated) — this event is listenable(device_ai_interaction_result). The handler receives the struct, whose Source and Target are both ?agent.
  • GuardSpawner.Enable() — turns the device on. Combined with its configured settings, this lets it spawn.
  • for (...) { GuardSpawner.Spawn() ; Sleep(0.5) }Spawn() tries to spawn one NPC each call. Sleep requires the <suspends> context that OnBegin provides.
  • In OnGuardEliminated, Result.Source? unwraps the optional eliminator — false if a non-agent (like the environment) made the kill.
  • DespawnAll(false) — removes every NPC the device owns. We pass false (no instigator) for the optional Instigator:?agent parameter.
  • Disable() stops further spawning (and despawns AIs too if Despawn AIs When Disabled is checked on the device).

Common patterns

Ambush: SpawnAt exact world positions

SpawnAt places an NPC at a precise vector3 and returns the spawned agent (or false if the spawn cap is reached). It's <suspends> because the NPC takes time to load.

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

ambush_device := class(creative_device):

    @editable
    Spawner : npc_spawner_device = npc_spawner_device{}

    OnBegin<override>()<suspends>:void =
        # Three ambush corners around the player's path.
        Corners := array:
            vector3{X := 1000.0, Y := 500.0, Z := 100.0}
            vector3{X := -800.0, Y := 600.0, Z := 100.0}
            vector3{X := 200.0, Y := -900.0, Z := 100.0}

        for (Pos : Corners):
            # SpawnAt returns ?agent — succeeds only if under the spawn cap.
            if (Enemy := SpawnAtPos(Pos)):
                Print("Ambusher placed.")

    # Helper wrapping the suspending SpawnAt call.
    SpawnAtPos(Pos : vector3)<suspends>:?agent =
        return Spawner.SpawnAt(Pos)

Wipe the field when the boss dies

Use GetAgents to inspect what the device currently owns, then DespawnAll crediting the player who landed the killing blow.

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

minion_clearer := class(creative_device):

    @editable
    MinionSpawner : npc_spawner_device = npc_spawner_device{}

    @editable
    BossSpawner : npc_spawner_device = npc_spawner_device{}

    OnBegin<override>()<suspends>:void =
        BossSpawner.EliminatedEvent.Subscribe(OnBossDown)
        BossSpawner.Spawn()

    OnBossDown(Result : device_ai_interaction_result):void =
        # How many minions are still out there?
        Minions := MinionSpawner.GetAgents()
        Print("Boss dead. Clearing {Minions.Length} minions.")

        # If a player got the boss, credit them with the cleanup too.
        if (Slayer := Result.Source?):
            MinionSpawner.DespawnAll(option{Slayer})
        else:
            MinionSpawner.DespawnAll(false)

Swap the NPC type before spawning

SetNPCCharacterDefinition is <decides> (it can fail) — it only succeeds if the new definition's character type matches the device's. Wrap it in if.

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

variant_spawner := class(creative_device):

    @editable
    Spawner : npc_spawner_device = npc_spawner_device{}

    # Assign an alternate NPC Character Definition asset here.
    @editable
    EliteDefinition : npc_character_definition = npc_character_definition{}

    OnBegin<override>()<suspends>:void =
        # Try to switch to the elite variant; only spawn if it took.
        if (Spawner.SetNPCCharacterDefinition[EliteDefinition]):
            Print("Swapped to elite NPCs.")
            Spawner.Enable()
            Spawner.Spawn()
        else:
            Print("Definition type mismatch — keeping current NPC.")

Gotchas

  • You must have a placed device. The npc_spawner_device{} default value is just a placeholder — bind the @editable field to a real device in the Details panel, or no NPCs spawn.
  • SpawnedEvent vs EliminatedEvent payloads differ. SpawnedEvent hands you a bare agent. EliminatedEvent hands you a device_ai_interaction_result struct — read .Source (the killer) and .Target (the victim), both ?agent, and unwrap with if (A := Result.Source?):.
  • SpawnAt is <suspends> and returns ?agent. You can only call it from a suspending context (like OnBegin or a <suspends> helper), and you must check the result — it returns false when the device's spawn cap is hit.
  • SetNPCCharacterDefinition can fail. It's <decides>, so call it with [ ] inside an if — it fails if the new definition is a different character type from the current one.
  • DespawnAll takes ?agent, not agent. Pass false for no instigator, or wrap a real agent as option{MyAgent} to credit the eliminations.
  • Disable() only despawns if configured. Whether disabling removes existing NPCs depends on the device's Despawn AIs When Disabled setting — use DespawnAll if you want a guaranteed clear.
  • No intfloat auto-conversion. Spawn positions need float components in vector3{X := 1000.0, ...}1000 (an int) won't compile there.

Guides & scripts that use npc_spawner_device

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

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