Creative devices in UEFN often come with a wide selection of user options that you can use to customize the way the device works. You can choose which player spawners belong to which team, what time of day it is, and even create custom classes and change the rules of the game.
Verse devices allow you to write your own Verse code to customize your game and affect the game world, but every time you change your code, you have to push your changes and test it again. Even small changes like adjusting the value of a number require recompiling.
Wouldn’t it be easier if you could change values on your Verse device without recompiling? Wouldn’t it be fun if you could customize your own user options? With the power editable properties, you can!
This guide shows how to make your Verse device more customizable by exposing editable properties that can be changed directly from the editor without modifying the Verse code.
Advantages of this approach include:
-
Faster iteration Test different configurations for your creative devices without any code changes.
-
Reusability Reuse the same device with different properties and values. For example, you could enable specific behaviors based on a
logic
type property that's exposed to the editor. -
Simplification Quickly see how a device can be used based on its properties instead of having to dive into the code to understand how it works.
Exposing a Variable to the Editor
To expose a variable to the editor as an editable property, you add the @editable
attribute to your variable.
Follow these steps to create a Verse device and expose a variable to the editor:
-
Create a new Verse device using Verse Explorer named
editable_testing_device
, and add it to your level. See Adding Your Verse Device to Your Level for steps. -
Open your Verse script in Visual Studio Code.
-
Under your
editable_testing_device
class definition, add a new integer namedBasicInt
. Above yourBasicInt
definition, add the@editable
attribute.using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # A Verse-authored creative device that can be placed in a level editable_testing_device := class(creative_device): # A basic editable integer. @editable BasicInt:int = 0
-
In
OnBegin()
, add aPrint()
statement to print out the value of yourBasicInt
.# A Verse-authored creative device that can be placed in a level editable_testing_device := class(creative_device): # A basic editable integer. @editable BasicInt:int = 0 # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= Print("The value of BasicInt is: {BasicInt}!")
-
Save your code and compile it to update your Verse device in the level.
-
In the UEFN Outliner, select your editable testing device to open its Details panel. In the Details panel, your device now has the property
BasicInt
.Changing the value of an editable property only changes for that instance of the device. If you have multiple Verse devices in your level, each can have a different value for this property.
-
Click Launch Session to test out your code. When the game begins, the value of
BasicInt
should be printed to the console. You can change the value ofBasicInt
on your Verse device without pushing changes, and the new value will be printed to the console.
Adding a Verse Reference to a Creative Device in Your Level
Verse devices can also reference other Creative devices. Referencing a device this way lets you call that device’s functions, such as turning a barrier on or off, or assigning a player to a team. Because your Verse device doesn’t know about these devices before the game starts, you can set them as editable references to run code on them at runtime.
Follow these steps to set up a reference to a Barrier device in your level, then turn it on and off on a loop:
-
Add a Barrier device to your level.
-
In Visual Studio Code, add a new editable attribute to your Verse device definition. In the following example, the Barrier device field
Barrier
is an editable property and has the default valuebarrier_device{}
but isn't connected to a Barrier device in your level.# A Verse-authored creative device that can be placed in a level editable_testing_device := class(creative_device): # A basic editable integer. @editable BasicInt:int = 0 # Reference to a Barrier device in the level. @editable Barrier:barrier_device = barrier_device{}
-
Add an editable
float
namedBarrierSleepTime
. This is the amount of time to wait before turning the barrier on or off again. Initialize this value to3.0
(three seconds).# Reference to a Barrier device in the level. @editable Barrier:barrier_device = barrier_device{} # The amount of time to wait before turning the barrier on or off. @editable BarrierSleepTime:float = 3.0
-
Write code to loop turning the barrier on and off. In
OnBegin()
, add aloop
expression. Inside theloop
, callBarrier.Disable()
to disable the barrier, then callSleep()
, passing theBarrierSleepTime
. CallBarrier.Enable()
to turn the barrier back on, andSleep()
again. YourOnBegin()
should now look like this:# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= Print("The value of BasicInt is: {BasicInt}!") # Loop turning the barrier on and off, waiting for a # BarrierSleepTime amount of seconds each time. loop: Barrier.Disable() Sleep(BarrierSleepTime) Barrier.Enable() Sleep(BarrierSleepTime)
-
Save your code and compile it to update your Verse device in the level.
-
In the UEFN Outliner, select your Verse device to open its Details panel. The property
Barrier
should now appear. -
You can now select a Barrier device in your level for your Verse device to reference:
-
Select Pick Actor from scene to pick the device in the viewport
-
Or use the dropdown and search for the device you want to reference.
-
-
Click Push Changes to update your edit session. When the game begins, the barrier should loop turning on and off. You can change the value of
BarrierSleepTime
on your Verse device to change the rate at which the barrier toggles.
Exposing an Array to the Editor
While it’s good to have a reference to the device you want to modify, what happens if you want to reference multiples of the same device? Creating an editable reference for each device isn’t scalable, so you can use arrays instead.
You can expose a resizable array to the editor to store and reference multiple objects at the same time. By iterating through the array, you can operate on each device in your level from a single block of code!
Follow these steps to add an editable array reference.
-
Replace the editable
Barrier
reference in youreditable_testing_device
with an editable array ofbarrier_device
namedBarriers
.# A Verse-authored creative device that can be placed in a level editable_testing_device := class(creative_device): # A basic editable integer. @editable BasicInt:int = 0 # Array of references to the Barrier devices in the level. @editable Barriers:[]barrier_device = array{}
-
In
OnBegin()
, remove the code inside theloop
expression and replace it with afor
expression. In thefor
expression, iterate through eachBarrier
inBarriers
, and callBarrier.Disable()
, thenSleep()
forBarrierSleepTimeSeconds
.# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= Print("The value of BasicInt is: {BasicInt}!") loop: # Iterate through each barrier in the Barriers array and turn it off. for: Barrier:Barriers do: Barrier.Disable() Sleep(BarrierSleepTime)
-
Add another
for
expression after the first that does the same thing, but callsBarrier.Enable()
instead ofBarrier.Disable()
. YourOnBegin()
function should now look like thi.s# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= Print("The value of BasicInt is: {BasicInt}!") loop: # Iterate through each barrier in the Barriers array and turn it off. for: Barrier:Barriers do: Barrier.Disable() Sleep(BarrierSleepTime) # Iterate through each barrier in the Barriers array and turn it on. for: Barrier:Barriers do: Barrier.Enable() Sleep(BarrierSleepTime)
-
Save your code and compile it. In the UEFN Outliner, copy your first Barrier device to create a line of barriers.
-
Select your Verse device to open its Details panel. In the Details panel, the Verse device now has the array property Barriers, but has no elements.
-
Click Add Element to add elements to your Barriers array. Repeat for each of your barriers in the level.
If you want to remove elements from your array in the editor: Choose Remove All Elements which deletes all elements in the array, or: Delete an individual element by expanding the additional actions for the element and choosing Delete.
-
Click Push Changes to update your edit session. When the game starts, your barriers should loop, turning off in sequence then on in sequence. You can change the BarrierSleepTime to change the rate they turn on and off.
Your code will iterate through each barrier in the array in the order that you set them on your Verse device. You can drag and reorder elements in the Barriers array on the details panel to change the order in which the barriers turn on and off.
Each copy of this editable_testing_device device that you place in the level will have its own editable values for Barriers
, which you can then use to change which Barrier devices the Verse device references.
Exposing Custom Types to the Editor
You can use custom classes to group data and functions to create custom behavior, and by exposing them to the editor you can assign their values just like a Verse device. In this example, you’ll build a custom class that stores an array of barriers. This way you can handle multiple arrays with only one Verse device!
Follow these steps to expose a custom type to the editor:
-
The following example defines a custom class named
barrier_array
that holds an array of Barrier devices. It uses the sameBarriers
array andBarrierSleepTime
float you defined earlier, so move those values into this class. It also defines a function namedBarrierSequence
to loop through each barrier in the array and turn it off, then repeats the process to turn each barrier back on. This is similar to the code you wrote before to turn off individual barriers, so you can move that code fromOnBegin()
into this class. This class also has theconcrete
specifier, which means that all your editables have to be initialized with a value, which is required if you want them to show up in the editor.# A class with editable values. This class needs the <concrete> specifier # to expose editable values to the editor. barrier_array := class<concrete>(): # Array of references to the Barrier devices in the level. @editable Barriers:[]barrier_device = array{} # The amount of time to wait before turning the barrier on or off. @editable BarrierSleepTime:float = 3.0 # Loops turning each barrier in the Barriers array on and off in sequence. BarrierSequence()<suspends>:void= loop: # Iterate through each barrier in the Barriers array and turn it off. for: Barrier:Barriers do: Barrier.Disable() Sleep(BarrierSleepTime) # Iterate through each barrier in the Barriers array and turn it on. for: Barrier:Barriers do: Barrier.Enable() Sleep(BarrierSleepTime)
-
As with Creative devices, you can define an array of a custom class. In your
editable_testing_device
class, define a new array ofbarrier_array
namedBarrierArrays
. If you add the@editable
tag to this array, you can initialize elements in the array straight from the editor. You can then call functions on each element of the array at runtime. InOnBegin()
, iterate through each element of theBarrierArrays
, andspawn{}
aBarrierSequence()
for each one. You need to spawn this function rather than call it since the function needs to run asynchronously.# A Verse-authored creative device that can be placed in a level editable_testing_device := class(creative_device): # An editable array of integers. @editable BarrierArrays:[]barrier_array = array{} # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= # Spawn a BarrierSequence function for each BarrierArray class. for: BarrierArray:BarrierArrays do: spawn{BarrierArray.BarrierSequence()}
Making an editable property an array of your custom types adds flexibility to the information you provide to your Verse device. For example, you can define your own gameboard class with device references. An array of these gameboards on your Verse device means that you can choose how many levels your game will have and give a unique setup for each. You can even define editable arrays in your class's definition to add more extensibility and customization to your information.
-
Save your code and compile it.
-
In the UEFN Outliner, select your Verse device to open its Details panel.
-
In the device's Details panel, the Verse device now has the section
BarrierArrays
. -
Expand the
BarrierArrays
section to see its properties. You can add elements to each of theBarriers
arrays, and change theBarrierSleepTime
for each of them. -
Click Push Changes to update your edit session. When the game starts, each array of barriers should loop, turning off in sequence, then on in sequence. You can change the BarrierSleepTime to change the rate at which they turn on and off.
Adding a Verse Reference to a Creative Device in Your Level
In addition to Creative devices, you can also reference Creative props on your Verse devices. Referencing Creative props in this way lets you use a number of useful functions, such as spawning props, changing their materials and mesh, and even animating them!.
This example will guide you through referencing a prop in your level, and using Verse to blink it on and off!
-
Create a new Verse device named
blinking_prop_device
, and open it in Visual Studio Code. -
At the top of your
blinking_prop_device
class definition, add an editablecreative_prop
reference namedBlinkingProp
.# Reference to a creative prop in the level. @editable BlinkingProp:creative_prop = creative_prop{}
-
In
OnBegin()
, in aloop
, callBlinkingProp.Hide()
to hide the prop. CallSleep()
for a short amount of time, then callBlinkingProp.Show()
to make the prop visible again. Finally, sleep again.using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # See https://dev.epicgames.com/documentation/en-us/uefn/create-your-own-device-in-verse for how to create a verse device. # A Verse-authored creative device that can be placed in a level blinking_prop_device := class(creative_device): # Reference to a creative prop in the level. @editable BlinkingProp:creative_prop = creative_prop{} # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= # Loop hiding and showing the creative prop. loop: BlinkingProp.Hide() Sleep(0.75) BlinkingProp.Show() Sleep(0.75)
-
Save and compile your code. Drag your blinking_prop_device into the level.
-
Drag a Creative prop into the level. (This example uses Chair01.) Set the Creative prop as the BlinkingProp on your Verse device.
-
Launch your edit session. When the game begins, the prop should blink on and off on a loop!
Tooltips and Categories
You can use Tooltips and Categories to organize your editable values and add tooltips to the editor.
For example, take a basic editable integer value:
@editable:
BasicInt:int = 0
You can enhance this editable value by adding a tooltip message. Adding a tooltip means that a message will be displayed when you mouse over the value in the editor. You can also add an array of categories, which sorts the editable field into categories on your Verse device. Both tooltips and categories take the message
type, and you can define and reuse them across your editable values.
IntsCategory<public><localizes>:message := "Integer Values"
# A Verse-authored creative device that can be placed in a level
editable_testing_device := class(creative_device):
# An editable integer with a tooltip and a category.
@editable:
# The tooltip for this editable.
ToolTip := EditableIntTip
# The categories this editable belongs to.
Categories := array{IntsCategory}
DetailedInt:int = 0
Now, when you mouse over this value in the editor, it will display the EditableIntTip
message! The value will also be organized into its own category, Integer Values, on your Verse device.
NPC Spawner Editables
Editable values also work with NPC Character definitions. By defining an editable value in your NPC Behavior Script, they’ll show up in the editor on NPC Spawners that use that behavior script.
using { /Fortnite.com/AI }
using { /Verse.org/Simulation }
NPCIntTip <public><localizes>:message := "Editables work with NPCs as well!"
# A Verse-authored NPC Behavior that can be used within an NPC Character Definition or an NPC Spawner device's NPC Behavior Script Override.
npc_with_editables := class(npc_behavior):
@editable:
# The categories this editable belongs to.
Categories := array{IntsCategory}
# The tool tip for this editable.
ToolTip := NPCIntTip
CustomInt:int = 0
@editable
UncategorizedInt:int = 0
# This function runs when the NPC is spawned in the world and ready to follow a behavior.
OnBegin<override>()<suspends>:void=
Print("The value of this character's int is {CustomInt}!")
Component Editables
You can define editable values in your Scenegraph components to expose them to the editor. Note that if you define categories for editables in your components, they’ll show up in their own category separate from the component.
In the following example, the CustomInt
, CustomFloat
, and UncategorizedInt
are all part of the same component_with_editables
Verse component. Because CustomInt
and CustomFloat
have defined categories, they’ll show up in the editor separately from the Verse component.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SceneGraph }
ComponentEditableTip<public><localizes>:message := "Editables also work with Components!"
# A Verse-authored component that can be added to entities
component_with_editables<public> := class(component):
# This editable will show up under the `Int Values` category.
@editable:
# The categories this editable belongs to.
Categories := array{IntsCategory}
# The tool tip for this editable.
ToolTip := ComponentEditableTip
CustomInt<public>:int = 10
# This editable will show up under the `Float Values` category.
@editable:
# The categories this editable belongs to.
Categories := array{FloatsCategory}
# The tool tip for this editable.
ToolTip := ComponentEditableTip
CustomFloat:float = 1.0
# This editable will show up under the `component_with_editables` category.
@editable:
# The tool tip for this editable.
ToolTip := ComponentEditableTip
UncategorizedInt:int = 0
Supported Editable Types
Currently, the following types can be exposed to the editor as editable properties:
logic
int
float
enum
string
- arrays of editable types
- maps of editable types
- structs of editable types
- class instances
Several other editable types exist, each with their own definition:
Editable Text Box
You can use an editable text box to create a string
message from the editor. Unlike a basic string
editable, the text box lets you define whether the message spans multiple lines, and the max length of the message in the text box.
# An editable string that displays as a text box in the editor.
# Editable text boxes currently do not support tooltips or categories.
@editable_text_box:
# Whether this text can span multiple lines.
MultiLine := true
# The maximum amount of characters this text block can display.
MaxLength := 32
MessageBox:string = "This is a short message!"
Editable text boxes currently do not support tooltips or categories.
Editable Slider
You can turn numeric parameters (int
, float
) into sliders using the editable slider type. This lets you change the editable value by dragging the slider in the editor. Sliders have several options, such as the minimum and maximum value of the slider, the amount the slider changes per each increment (the SliderDelta
), and the amount required to drag to increment the slider.
# An editable slider that uses the float type. You can drag the slider in the editor to increase
# or decrease the value.
@editable_slider(float):
# The categories this editable belongs to.
Categories := array{FloatsCategory}
# The tool tip for this editable.
ToolTip := SliderTip
# The minimum value of each component. You cannot set an editable value for this number lower
# than the MinComponentValue.
MinValue := option{0.0}
# The maximum value of each component. You cannot set an editable value for this number higher
# than the MaxComponentValue.
MaxValue := option{10.0}
# The amount the slider value increases or decreases per delta.
SliderDelta := option{1.0}
# The amount to scale the slider delta by.
SliderExponent := option{1.0}
# The sensitivity of the mouse movement required to cause a delta increase.
MouseLinearDeltaSensitivity := 0.25
# The amount of pixels required to move the mouse to cause a delta increase.
MouseShiftMovePixelPerDelta := 0.25
FloatSlider:float = 1.0
Editable Number
Editable numbers have a key advantage over regular editable numerics, in that you can set the minimum and maximum value of the editable. Defining a MinValue
and MaxValue
means that the editable value will be constrained between these two values.
# An editable number with minimum and maximum
@editable_number(int):
# The tool tip for this editable.
ToolTip := EditableIntTip
# The category this editable belongs to.
Categories := array{IntsCategory}
# The minimum value of each component. You cannot set an editable value for this number lower
# than the MinComponentValue.
MinValue := option{0}
# The maximum value of each component. You cannot set an editable value for this number higher
# than the MaxComponentValue.
MaxValue := option{10}
MinAndMaxInt:int = 1
Editable Vector Slider
In addition to numerics, sliders are also supported for vectors through the editable vector slider type. This creates sliders for each component of your vector and allows you to define min and max values as well as how much the value increases or decreases as you drag the slider. Vector sliders can be of type vector2
, vector2i
, or vector3
.
Two other options, ShowPreserveRatio
and ShowNormalize
are also present. When set to true, these expose two extra buttons in the editor. The preserve-ratio button locks your vector scaling so that all components scale uniformly. This means increasing or decreasing one component of the vector will affect the others to preserve the ratio between them. The normalize button scales each component of the vector to create a unit vector (a vector with a length of one).
# An editable vector slider. You can drag to change the values of each of the vector components.
@editable_vector_slider(float):
# The tool tip for this editable.
ToolTip := VectorSliderTip
# The categories this editable belongs to.
Categories := array{FloatsCategory}
# Shows the option to preserve the ratio between vector values in the editor.
ShowPreserveRatio := true
# Shows the option to normalize the vector in the editor.
ShowNormalize := true
# The minimum value of each component. You cannot set an editable value for this number lower
# than the MinComponentValue.
MinComponentValue := option{0.0}
# The maximum value of each component. You cannot set an editable value for this number higher
# than the MaxComponentValue.
MaxComponentValue := option{10.0}
# The amount the slider value increases or decreases per delta.
SliderDelta := option{0.5}
# The sensitivity of the mouse movement required to cause a delta increase.
MouseLinearDeltaSensitivity := 0.25
# The amount of pixels required to move the mouse to cause a delta increase.
MouseShiftMovePixelPerDelta := 0.25
FloatVectorSlider:vector3 = vector3{X := 1.0, Y := 2.0, Z := 3.0}
The ShowNormalize
option is only available when using float vectors, so you cannot use it with vector2i
.
Editable Vector Number
Editable vector numbers have similar settings to vector sliders, but without the slider component. They allow you to set minimum and maximum values, and also expose the preserve ratio and normalize buttons. Vector numbers can be of type vector2
, vector2i
, or vector3
.
# An editable vector number, which can be a vector2, vector2i, or vector3.
@editable_vector_number(float):
# The categories this editable belongs to.
Categories := array{FloatsCategory}
# The tool tip for this editable.
ToolTip := VectorFloatTip
# Shows the option to preserve the ratio between vector values in the editor.
ShowPreserveRatio := true
# Shows the option to normalize the vector in the editor.
ShowNormalize := true
# The minimum value of each component. You cannot set an editable value for this number lower
# than the MinComponentValue.
MinComponentValue := option{0.0}
# The maximum value of each component. ou cannot set an editable value for this number higher
# than the MaxComponentValue.
MaxComponentValue := option{2.0}
FloatVector:vector2 = vector2{X := 1.0, Y := 2.0}
The ShowNormalize
option is only available when using float vectors, so you cannot use it with vector2i
.
Editable Container
Editable containers allow you to choose whether reordering of elements is allowed. Currently, only arrays are supported.
# An editable container of values. Currently this only supports arrays.
@editable_container:
# The category this editable belongs to.
Categories := array{IntsCategory}
# The tool tip for this editable.
ToolTip := IntArrayTip
# Whether dragging elements to reorder this container is allowed.
AllowReordering := false
IntArray:[]int = array{}