Overview
A subtype cast is how you tell Verse "I know this generic object is really a specific type — let me use it as that type." It solves a very common UEFN problem: functions like FindCreativeObjectsWithTag() / GetCreativeObjectsWithTag() return []creative_object_interface, because a single tag might match many different kinds of actors. That interface has almost no useful methods on it. To call TurnOn(), SetMesh(), or Toggle(), you must first cast the generic value into the concrete class.
The casting syntax is TargetType[value]. The square brackets mean it is a failable (fallible) expression: if value is not actually of TargetType, the cast fails and the surrounding if/for branch is skipped. This is exactly what you want when a tag matches ten props but only three are lights — the cast quietly filters out everything that isn't a light.
Reach for subtype casting whenever you:
- Grab a batch of tagged actors and need to drive them as a specific device.
- Store a mixed list of objects and want to act only on the ones of a certain type.
- Convert a base
creative_objectreference into acreative_propso you can move or reskin it.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: A vault room full of lights. When a player steps on a pressure plate (a trigger_device), every light tagged alarm_light snaps on red-alert style — we find them all by tag, cast each generic actor to customizable_light_device, and call TurnOn(). Step off, and we TurnOff() them.
We'll add a power_light tag in UEFN to each Customizable Light we want controlled, then let Verse discover them at runtime — no need to wire up a hundred editable fields.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Simulation/Tags }
# Tag placed on every Customizable Light we want to control.
alarm_light := class(tag){}
vault_alarm := class(creative_device):
# The pressure plate the player steps on.
@editable
AlarmPlate : trigger_device = trigger_device{}
# Cache the lights we find so we only search once.
var Lights : []customizable_light_device = array{}
OnBegin<override>()<suspends>:void =
# 1. Find every actor carrying the alarm_light tag.
FoundActors := GetCreativeObjectsWithTag(alarm_light{})
# 2. Cast each generic actor into the concrete light device.
for (Actor : FoundActors):
if (Light := customizable_light_device[Actor]):
set Lights += array{Light}
# 3. React to the plate being stepped on / off.
AlarmPlate.TriggeredEvent.Subscribe(OnStepOn)
# Player stepped on the plate -> raise the alarm.
OnStepOn(Agent : ?agent):void =
for (Light : Lights):
Light.TurnOn()
Line by line:
alarm_light := class(tag){}declares a gameplay tag as a type. In UEFN you add this tag to each light's Gameplay Tags list.@editable AlarmPlate : trigger_deviceis the placed plate. Any placed device you call must be an@editablefield on acreative_deviceclass — a bareSomeDevice.Method()won't compile.var Lights : []customizable_light_devicecaches the results so we don't re-scan every step.GetCreativeObjectsWithTag(alarm_light{})returns[]creative_object_interface— the generic list.if (Light := customizable_light_device[Actor])is the subtype cast. The square brackets make it failable: for actors that aren't lights, the cast fails and theifbody is skipped, so only real lights land inLights.set Lights += array{Light}appends each successfully-cast light.AlarmPlate.TriggeredEvent.Subscribe(OnStepOn)wires the plate's event to our handler (subscribe inOnBegin; the handler is a class-scope method).- In
OnStepOnwe loop the cached lights and call the real device methodTurnOn().
Common patterns
Pattern 1 — Toggle tagged lights with a button. Same cast, but we call Toggle() so one button flips them all on/off.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Simulation/Tags }
room_light := class(tag){}
light_switch := class(creative_device):
@editable
SwitchButton : button_device = button_device{}
var Lights : []customizable_light_device = array{}
OnBegin<override>()<suspends>:void =
for (Actor : GetCreativeObjectsWithTag(room_light{})):
if (Light := customizable_light_device[Actor]):
set Lights += array{Light}
SwitchButton.InteractedWithEvent.Subscribe(OnPressed)
OnPressed(Agent : agent):void =
for (Light : Lights):
Light.Toggle()
Pattern 2 — Cast a base object into creative_prop to reskin it. Tags can match spawned props too. Here we cast to creative_prop and call Hide() on each to make a set of decoy props vanish.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Simulation/Tags }
decoy := class(tag){}
decoy_remover := class(creative_device):
@editable
RemoveTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
RemoveTrigger.TriggeredEvent.Subscribe(OnTriggered)
OnTriggered(Agent : ?agent):void =
for (Actor : GetCreativeObjectsWithTag(decoy{})):
if (Prop := creative_prop[Actor]):
Prop.Hide()
Pattern 3 — Dim tagged lights on demand. After caching lights via cast, drive a different method — DimLight() — to fade the room.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Simulation/Tags }
mood_light := class(tag){}
mood_setter := class(creative_device):
@editable
DimButton : button_device = button_device{}
var Lights : []customizable_light_device = array{}
OnBegin<override>()<suspends>:void =
for (Actor : GetCreativeObjectsWithTag(mood_light{})):
if (Light := customizable_light_device[Actor]):
set Lights += array{Light}
DimButton.InteractedWithEvent.Subscribe(OnDim)
OnDim(Agent : agent):void =
for (Light : Lights):
Light.DimLight()
Gotchas
- The cast is failable, so it needs a failure context.
customizable_light_device[Actor]must live insideif,for, or another failable position. Writing it as a plain statement won't compile. - Use
{}on the tag when calling the function.GetCreativeObjectsWithTag(alarm_light{})— you pass a tag value, so construct it withalarm_light{}, not the bare type name. GetCreativeObjectsWithTagis deprecated in favor ofFindCreativeObjectsWithTag, but it still works and returns the same[]creative_object_interface. Either way the casting technique is identical.- Cast in
OnBegin, cache the result. Re-scanning by tag on every trigger fire is wasteful. Cast once, store the concrete devices in avar []customizable_light_device, then just call methods on the cached list. - A wrong-type cast doesn't crash — it just fails. If one of your tagged actors is a barrier instead of a light,
customizable_light_device[Actor]silently fails and skips it. That's a feature: it filters your mixed list for free, but it also means a mistyped tag can leaveLightsempty with no error. ?agentvsagenthandlers.trigger_device.TriggeredEventhands you a?agent(optional) — unwrap withif (A := Agent?):before using the player.button_device.InteractedWithEventhands a non-optionalagentdirectly.- Int↔float never auto-converts. If you later mix casting with brightness math, remember Verse won't quietly promote an
intto afloat.