Added a link to a tutorial page. |
TheJebForge (talk | contribs) Apparently changing DynVar component rather than using ProtoFlux write dyn var node, will have a frame delay before you'll get the most recent value |
||
Line 142: | Line 142: | ||
<translate><!--T:91--> Dynamic variables are also global by default. If you [[drive]] a Dynamic variable, the variable's value becomes inherently local. If you have another instance of the variable that's not driven, it will cause the driven value to synchronize between all clients in the session, resulting in value seemingly glitching.</translate> | <translate><!--T:91--> Dynamic variables are also global by default. If you [[drive]] a Dynamic variable, the variable's value becomes inherently local. If you have another instance of the variable that's not driven, it will cause the driven value to synchronize between all clients in the session, resulting in value seemingly glitching.</translate> | ||
Driving or writing to value of [[Component:DynamicValueVariable|DynamicValueVariables]] or [[Component:DynamicReferenceVariable`1|DynamicReferenceVariables]] components, and then trying to read the value with ProtoFlux using [[ProtoFlux:Dynamic Variable Input|Dynamic Variable Input]] or [[ProtoFlux:Read Dynamic Variable|Read Dynamic Variable]], will have old value as it takes a frame for [[Component:DynamicVariableSpace|DynamicVariableSpace]] to receive that change from the component. So if it's happening every frame (which would be the case for driving), the mentioned nodes will give you value from previous frame rather than the most current value. Using [[ProtoFlux:Write Dynamic Variable|Write Dynamic Variable]] will not have the delay and both Dynamic Variable Input and Read Dynamic Variable will provide the most recent value. | |||
Revision as of 14:54, 7 August 2024
Overview
Dynamic variables allow you to read and write data by name in the context of a Slot hierarchy. This makes it easy to manage data in large systems; every bit of data is clearly labeled, and you can break data into multiple spaces to keep your systems separate.
There is a quick-start guide for Dynamic Variables: How To Use Dynamic Variables
Naming Restrictions
When using Dynamic Variables there are some restrictions and limitations on naming both spaces and variables within those spaces.
Space and Variable Names cannot contain:
- Any symbols
- As defined in C# Char.IsSymbol
- Any Punctuation / Whitespace
- As defined in C# Char.IsPunctuation and C# Char.IsWhiteSpace
- Except for period (.), underscore (_) and space ( ).
Usage
Optionally, the name can be prefixed by the name of a space, terminated by a /, to choose a specific variable space to use. This is useful to distinguish between unrelated systems that all use dynamic variables.
Some valid names include:
- Health -- no space defined, named Health
- World/Color -- named Color, in the World space
- MyCoolSystem/Score -- named Score, in the MyCoolSystem space
Spaces
Dynamic variables can live anywhere in or under the slot containing a DynamicVariableSpace component.
So, a variable space on the world root can be used from anywhere, whilst a variable space on your avatar can be used from anything stored in your avatar.
Variables
The simplest way to use dynamic variables is to use the DynamicValueVariable<T> and DynamicReferenceVariable<T> components. These are for value (int, float, String, etc.) and reference (Slot, User, etc.) types, respectively. DynamicTypeVariable exists to store Types.
These components store a value or reference directly. If two variable components have the same name, then they will have identical contents.
Fields
If you want to use an existing field or reference as the contents of a dynamic variable, you can use the DynamicField<T> or DynamicReference<T> components. Instead of storing something directly, they point at a field that contains a value or reference type, respectively.
As with variables there is a variant for Type
fields: DynamicTypeField
(TODO: clarify value vs. reference types; I think this isn't fully correct)
Drivers
You can use the contents of a dynamic variable to drive a field or reference, using the DynamicValueVariableDriver<T> and DynamicReferenceVariableDriver<T> components.
Unlisted types
When creating a dynamic variable component, you will be given a list of "common types". If the type you seek is not in that list, you will have to enter it by hand. See Complex Types in Components.
Binding
Creating, duplicating, or moving a dynamic variable requires binding that variable to a space. This is a process that happens automatically but isn't perfect yet. (see Warning)
In essence it starts searching for a matching dynamic variable space at the slot of the dynamic variable.
If there is no match, it tries the parent slot, its parent etc. until a matching space is found.
Variables with explicitly given space names only match spaces with the same name.
Variables without explicit space name match all spaces that are not OnlyDirectBinding
The following image will demonstrate the differences in binding:
- I:
A
is connected toInner
becauseInner
is notOnlyDirectBinding
. - II/III: Both variables are bound explicitly.
- IV:
A
ignoresInner
becauseInner
isOnlyDirectBinding
. - V/VI: Both variables are bound explicitly.
- VII/IX: There is no matching dynamic variable space. Both variables are not bound.
- VIII: The variable is explicitly bound to
World
. - I and II share the same value.
- III, IV and VI share the same value.
Warning
In a few use-cases, binding may take a small amount of time, before which the dynamic variable can appear to be present, but not be readable or writable. Therefore, if you create a dynamic variable using the Create Dynamic Variable or Write Or Create Dynamic Variable ProtoFlux Node, or cause it to be duplicated using the Duplicate Slot ProtoFlux Node, or cause it to be moved using the Set Parent ProtoFlux Node, you may find it necessary to add an Delay Updates or Updates Delay With Data ProtoFlux Node afterwards in order to ensure the dynamic variables have been bound by the time you use them. A delay of 1 to 3 updates usually suffices. Creating DynamicValueVariables on already existing Dynamic Variable Space doesn't require any delays.
Dynamic variables are also global by default. If you drive a Dynamic variable, the variable's value becomes inherently local. If you have another instance of the variable that's not driven, it will cause the driven value to synchronize between all clients in the session, resulting in value seemingly glitching.
Driving or writing to value of DynamicValueVariables or DynamicReferenceVariables components, and then trying to read the value with ProtoFlux using Dynamic Variable Input or Read Dynamic Variable, will have old value as it takes a frame for DynamicVariableSpace to receive that change from the component. So if it's happening every frame (which would be the case for driving), the mentioned nodes will give you value from previous frame rather than the most current value. Using Write Dynamic Variable will not have the delay and both Dynamic Variable Input and Read Dynamic Variable will provide the most recent value.
Example Applications
The following examples will demonstrate a few use-cases of dynamic variables. There is a focus on how to use them to create separate objects
Modules within an object
Dynamic variables within an object allow modularization. Different modules would be connected via dynamic variables within the space located at the root of the object. If all hard-coded references going in or out of a module are eliminated you can replace it with a different variant/version without additional setup. Module-local variables can be created with a dynamic variable space located at the root of the module. Use appropriately named spaces to differentiate between the two. To make available variables more obvious to other people - including you in 6 months - it is recommended to place all dynamic variables within a dedicated slot hierarchy.
Commonly used names for such hierarchies are:
- DV
- DynVar
- Vars
- etc.
A modular object could look like this:
- Project (Space:
MyProject
)- Dynamic Variables
- projectVar: String (Dynamic variable
projectVar
of type String)
- projectVar: String (Dynamic variable
- Module: UI (i.e. MeshRenderer or Canvas plus Colliders), may contain:
- Dynamic Variable Drivers → Visuals
- Button Interactions → Dynamic Variables
- Editors ↔ Dynamic Variables
- Module: Logic (Space:
Logic
)- Dynamic Variables
- ProtoFlux (may read, write or even drive dynamic variables of space
MyProject
)
- Dynamic Variables
Configurable objects
Dynamic variables make it possible to access other object's properties.
Assuming objects with a dynamic variable space, a collider and a string variable named Description
you could then create a separate tool that reads and displays the Description
of the object it is pointed at. The same tool could be extended to edit descriptions.
The same concept can also be applied to template slots used within a project. Their instances can be interacted with using dynamic variables.
World/User variables
There are already pre-made dynamic variable spaces:
World
on Root (OnlyDirectBinding
)User
on each User Root Slot (OnlyDirectBinding
)Dash
on Slot of UserSpaceRadiantDash
They can be used for states that are shared by many objects (i.e. day/night toggle, performance) or to broadcast information into the world. (BeatLink, library objects like the Redprint manager)
See Dynamic Variable Naming Standard for a more detailed listing.