Overview
The gameplay_controls_device represents a single gameplay control scheme you configure in UEFN (button mappings, sensitivity, and which inputs are allowed). What makes it powerful is that controls live on a per-player stack: when you push a scheme onto a player, it becomes the active control mode; when you pop it, the player falls back to whatever scheme was beneath it.
This solves a very common game-design problem: temporary control modes. A few concrete examples:
- A player steps into a turret — push a "turret aim" scheme that disables jumping. Step out — pop it, normal movement returns.
- A stealth section where sprint is removed and crouch is forced — push on entry, pop on exit.
- A mini-game with a custom control layout that only applies while the player is inside the arena.
Because it's a stack, you can layer schemes and they unwind cleanly in reverse order. The device exposes six methods: Enable/Disable toggle whether the device participates at all, while AddTo/AddToAll push the scheme onto one player or everyone, and RemoveFrom/RemoveFromAll pop it back off.
Note:
gameplay_controls_deviceis anabstractbase. In UEFN you'll place a concrete control-scheme device (its specific control-mode variant) — but in Verse you reference it through thisgameplay_controls_devicetype, and these are the methods you call.
API Reference
gameplay_controls_device
Used to update the gameplay controls scheme based on current control mode.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
gameplay_controls_device<public> := class<abstract><epic_internal>(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. |
AddTo |
AddTo<public>(Agent:agent):void |
Adds the gameplay control to the Player's gameplay controls stack and pushes it to be the active control. |
AddToAll |
AddToAll<public>():void |
Adds the gameplay control to all Agents gameplay controls stack and pushes it to be the active control. |
RemoveFrom |
RemoveFrom<public>(Agent:agent):void |
Removes the gameplay control from the Agent's gameplay controls stack and pops from being the active control replacing it with the next one in the stack. |
RemoveFromAll |
RemoveFromAll<public>():void |
Removes the gameplay control from all Agents gameplay controls stack and pops from being the active control replacing it with the next one in the stack. |
Walkthrough
Scenario: We have a turret pad. When a player steps onto a trigger volume (the turret seat), we enable a custom "turret controls" scheme and push it onto that player. When they step onto an exit trigger, we pop the scheme so their normal controls come back.
We'll use a trigger_device for the seat and another for the exit. The triggers' TriggeredEvent is a listenable(?agent), so we unwrap the agent before calling AddTo/RemoveFrom.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# A turret seat that swaps the player's control scheme while they're sitting.
turret_seat_device := class(creative_device):
# The custom control scheme configured in UEFN (e.g. turret aim controls).
@editable
TurretControls:gameplay_controls_device = gameplay_controls_device{}
# The trigger the player steps on to take the seat.
@editable
EnterSeatTrigger:trigger_device = trigger_device{}
# The trigger the player steps on to leave the seat.
@editable
ExitSeatTrigger:trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
# Make sure the control device is active before we ever push it.
TurretControls.Enable()
# Wire up the seat enter / exit triggers.
EnterSeatTrigger.TriggeredEvent.Subscribe(OnEnterSeat)
ExitSeatTrigger.TriggeredEvent.Subscribe(OnExitSeat)
# Called when a player steps onto the seat trigger.
OnEnterSeat(Agent:?agent):void =
if (Player := Agent?):
# Push the turret scheme onto this player's control stack.
# It becomes their active control mode immediately.
TurretControls.AddTo(Player)
# Called when a player steps onto the exit trigger.
OnExitSeat(Agent:?agent):void =
if (Player := Agent?):
# Pop the turret scheme; the player's previous controls return.
TurretControls.RemoveFrom(Player)
Line by line:
@editable TurretControls:gameplay_controls_device— declares a field you bind, in the UEFN Details panel, to the control-scheme device you placed. A bare device variable can't be called; the@editablefield is what makesTurretControls.AddTo(...)legal.OnBegin<override>()<suspends>:void =— the entry point that runs when the game starts.TurretControls.Enable()— turns the device on so it's eligible to be pushed. If it's disabled, pushing it has no effect.EnterSeatTrigger.TriggeredEvent.Subscribe(OnEnterSeat)— registers our handler method. The handler signature must accept(Agent:?agent)becauseTriggeredEventis alistenable(?agent).if (Player := Agent?):— the agent arrives wrapped in an option; this unwraps it. If there's no agent we skip safely.TurretControls.AddTo(Player)— pushes the scheme onto this specific player. Other players are unaffected.TurretControls.RemoveFrom(Player)— pops it back off, restoring the player's prior control mode.
Common patterns
Push a control scheme on EVERY player when an event starts
Use AddToAll() to apply the scheme to the whole lobby at once — great for a phase of a round where everyone shares special controls (e.g. a vehicle-only segment).
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
phase_controls_device := class(creative_device):
@editable
SpecialControls:gameplay_controls_device = gameplay_controls_device{}
# A button that starts the special phase for everyone.
@editable
StartPhaseButton:button_device = button_device{}
OnBegin<override>()<suspends>:void =
SpecialControls.Enable()
StartPhaseButton.InteractedWithEvent.Subscribe(OnStartPhase)
OnStartPhase(Agent:agent):void =
# Push the scheme onto every player's control stack at once.
SpecialControls.AddToAll()
Pop the scheme off everyone when the phase ends
RemoveFromAll() unwinds the stack for all players, returning each to their previous control mode.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
end_phase_controls_device := class(creative_device):
@editable
SpecialControls:gameplay_controls_device = gameplay_controls_device{}
# A trigger that fires when the special phase ends.
@editable
EndPhaseTrigger:trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
EndPhaseTrigger.TriggeredEvent.Subscribe(OnEndPhase)
OnEndPhase(Agent:?agent):void =
# Remove the scheme from all players, restoring normal controls.
SpecialControls.RemoveFromAll()
Disable the device to block all pushes
If you want to globally turn a control scheme off (so no further AddTo calls take effect), call Disable(). Re-enable later with Enable().
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
controls_toggle_device := class(creative_device):
@editable
StealthControls:gameplay_controls_device = gameplay_controls_device{}
# Toggles the stealth control scheme on / off globally.
@editable
ToggleButton:button_device = button_device{}
var Active:logic = false
OnBegin<override>()<suspends>:void =
ToggleButton.InteractedWithEvent.Subscribe(OnToggle)
OnToggle(Agent:agent):void =
if (Active?):
StealthControls.Disable()
set Active = false
else:
StealthControls.Enable()
set Active = true
Gotchas
- It's a stack, not a switch. Every
AddTopushes a new active scheme; everyRemoveFrompops one. If you push twice and pop once, the scheme is still active. Keep your pushes and pops balanced per player, or you'll get "stuck" control modes. - Enable before you push. If the device is
Disable()d, callingAddTo/AddToAllwon't make the scheme active. CallEnable()once inOnBegin(or whenever you want pushes to start working). AddTois per-player;AddToAllis everyone. Don't loop over players callingAddTowhen you meanAddToAll— and don't callAddToAllwhen you only want one player to get the new controls.- Unwrap the option agent.
trigger_device.TriggeredEventhands you(Agent:?agent). You must doif (Player := Agent?):before passing it toAddTo/RemoveFrom, which expect a plainagent. - The type is abstract.
gameplay_controls_deviceisabstract— you can't construct a meaningful one in code; you bind the@editablefield to a concrete control-scheme device placed in your level. The= gameplay_controls_device{}default is just a placeholder until you assign it in UEFN. - Removing when nothing was pushed. Calling
RemoveFrom/RemoveFromAllwhen the scheme isn't on a player's stack simply does nothing harmful, but it also won't "reset" controls — there has to be a matching prior push.