User:Yosh/sandbox: Difference between revisions

From Resonite Wiki
dynamic variables
 
Marked this version for translation
 
(12 intermediate revisions by the same user not shown)
Line 1: Line 1:
'''Dynamic variables''', commonly shorted to '''dyn vars''' or '''dynvars''', is a system of data storage wherein one can store arbitrary, scoped data under slot heirarchies with arbitrary names, akin to that of an [https://en.wikipedia.org/wiki/Associative_array associative array]. Their usage is usually found in large systems with many moving parts, but can nonetheless be useful as easy "global" values that can be changed on an object.
<languages></languages>


== Usage ==
{{Infobox Component
Dynamic variables as a whole are managed with two parts: ''dynamic variable spaces'' and ''dynamic variables''. The [[Component:DynamicVariableSpace|DynamicVariableSpace]] component defines a dynamic variable space, while any one of the [[Component:DynamicValueVariable|DynamicValueVariable]], [[Component:DynamicReferenceVariable|DynamicReferenceVariable]], [[Component:DynamicTypeVariable|DynamicTypeVariable]] components define a dynamic variable. Dynamic variable spaces and names must not contain symbols, punctuation, or whitespace, <em>except</em> for period (<code>.</code>), underscore (<code>_</code>), and space (<code> </code>). To check if a character is unable to be used in a dynamic variable name, one can use the [[ProtoFlux:Is Symbol|Is Symbol]], [[ProtoFlux:Is Punctuation|Is Punctuation]], and [[ProtoFlux:Is White Space|Is White Space]] ProtoFlux nodes, taking care of the three exceptions above.
|Image=ValueGradientDriver`1Component.png
|Name=ValueGradientDriver
}}


The process of a dynamic variable being associated with a given space is called ''binding''. The <code>VariableName</code> of a dynamic variable component can be one of the following two forms: <code>VariableName</code> or <code>VariableSpaceName/VariableName</code>. The former represents ''indirect binding'', while the latter represents ''direct binding''. A dynamic variable component will traverse up the slot heirarchy, including its current slot, looking for an applicable variable space to bind to. If a dynamic variable is indirectly binding, it will bind to the first dynamic variable space that does not have <code>OnlyDirectBinding</code> set to <code>True</code>. If a dynamic variable is directly binding, it will bind to the first dynamic variable space that matches its name. If a dynamic variable does not find a dynamic variable space that it can bind to, it will not be accessible outside of the component itself, essentially reducing to a glorified [[Component:ValueField|ValueField]]. A dynamic variable will go through this binding process every time any part of the component changes.
<translate>
<!--T:1-->
The '''ValueGradientDriver''' component changes the value of the field defined in <code>Target</code> based on the items in the <code>Points</code> list and their <code>Position</code> in relation to the <code>Progress</code> value.
</translate>


{{Note|Currently, there exist a few instances where created variables do not instantly bind/rebind to a dynamic variable space, requiring a[[ProtoFlux:Delay Updates|Delay Updates]] of 2+ updates. These include [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/1394 creating new dynamic reference variables], [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/2717 deleting dynamic variables], changing the name of a dynamic variable or dynamic variable space, and any instance where there is a dynamic variable space change without a component update, such as [https://github.com/Yellow-Dog-Man/Resonite-Issues/issues/1690 duplicating slots containing a dynamic variable space] or reparenting a slot containing a dynamic variable under a new dynamic variable space. If you find your dynamic variables to be behaving weirdly, try adding a delay of 2 or more updates between such operations.|warning}}
== <translate><!--T:2--> Fields</translate> ==


=== Dynamic Fields ===
{{Table ComponentFields
It is also possible to interface with an existing [[Type:IField|IField]] as if it were a dynamic variable. This is done by attaching a [[Component:DynamicField|DynamicField]] component (for [[Type:IValue`1|IValue]] types), [[Component:DynamicReference|DynamicReference]] component (for [[Type:SyncRef`1|SyncRef]] types), or [[Component:DynamicTypeField|DynamicTypeField]] component (for the [[Type:Type|Type]] type), then dragging the target field into the <code>TargetField</code> field.
|Progress|Float|<translate><!--T:3--> Controls which items from the <code>Points</code> list will be used to drive the value of <code>Target</code></translate>
|Target|{{RootFieldType|FieldDrive`1|T}}|TypeAdv1=true|<translate><!--T:4--> The field that this component will drive the value of</translate>
|Interpolate|Bool|<translate><!--T:5--> Controls whether or not this component will interpolate (or blend) between the nearest two <code>Points</code> to the current <code>Progress</code> value.</translate>
|Points|{{RootFieldType|SyncList`1|[[#Point|Point]]&lt;T&gt;}}|TypeAdv3=true|<translate><!--T:6--> A list of items indicating their <code>Position</code> (in relation to <code>Progress</code>), and a <code>Value</code></translate>
}}


=== Reading and Writing ===
== <translate><!--T:7--> Usage</translate> ==
Dynamic variables can be read in any fashion one sees fit, such as copying from the variable field, sourcing the variable field, or using the [[ProtoFlux:Read Dynamic Variable|Read Dynamic Variable]] node. Dynamic variables can be written to via the [[ProtoFlux:Write Dynamic Variable|Write Dynamic Variable]] or [[ProtoFlux:Write Or Create Dynamic Variable|Write Or Create Dynamic Variable]] nodes. Additionally, there exists [[Component:DynamicValueVariableDriver|DynamicValueVariableDriver]] and [[Component:DynamicReferenceVariableDriver|DynamicReferenceVariableDriver]] components. These can be used to drive other fields with the value of a dynamic variable.


{{Note|Do <em>not</em> write to the <code>Value</code> or <code>Reference</code> field directly. Additionally, do not write to the pointed field of a DynamicField directly. Always use the ProtoFlux nodes for writing to a dynamic variable. Otherwise, you will need to wait 2+ updates before the variable actually propagates the new value when reading the dynamic variable back. Reading can be done in any fashion and will update instantly upon the variable being written to.|warning}}
<translate>
<!--T:8-->
Each point in the <code>Points</code> list has a <code>Position</code> field and <code>Value</code> field. The <code>Position</code> field is used for comparison with the component's <code>Progress</code> field, while the <code>Value</code> field is the value used for driving the field in <code>Target</code>.


==== Driving Dynvars ====
<!--T:9-->
Driving dynamic variables must be done with caution. For one, one must drive the value field of the dynamic variable, which incurs the 2+ update delay regarding indirectly writing to dynamic variables. Additionally, if a dynamic variable is being driven, it is <em>crucial</em> that <em>all</em> instances of the dynamic variable are driven by the same value. Otherwise, clients will fight over which value is the "true" value of the dynamic variable and cause inconsistent behavior.
When <code>Interpolate</code> is checked, the value stored in <code>Target</code> is linearly interpolated between the <code>Value</code>s of the two points surrounding the current <code>Progress</code>. When unchecked, the output value is simply set to the <code>Value</code> of the closest point before the current <code>Progress</code>. The only exception to this is when no point exists before the current <code>Progress</code>, in which case the first point after the current <code>Progress</code> is used.


== Example Applications ==
<!--T:10-->
If two points have the same <code>Position</code>, then the point of greatest index takes priority if the value is not interpolated or if the positions are exactly equal to the current <code>Progress</code>. ''During'' interpolation, however, the point of ''least'' index takes priority.
</translate>
 
== <translate><!--T:11--> Examples</translate> ==
 
<gallery widths=560px heights=480px>
File:component_example_ValueGradientDriver.webm|alt=<translate><!--T:12--> A ValueGradientDriver is set up with five float values. Index 0 has position 0.00 and value 0, index 1 has position 0.77 and value 2, index 2 has position 0.25 and value 4, index 3 has position 0.67 and value 6, and index 4 has position 1.00 and value 8. As progress moves from 0 to 1, the target field is linearly interpolated between the values of indices 0, 2, 3, 1, then 4. Once interpolation is unchecked, the target field is merely set to the previous index value.</translate>|<translate><!--T:13--> General usage of the component, showing interpolation and non-interpolation between five float values.</translate>
File:Component_example_ValueGradientDriver_IndexOfMax.webp|alt=<translate><!--T:14--> A ValueGradientDriver is set up with five int values. The progress is fixed at 1 and each point's value is set to its index. Interpolation is disabled. The index of the point with the greatest position is output.</translate>|<translate><!--T:15--> An unorthodox yet valid usage of the component, as way to find the index of the maximum value in a list of floats (as the <code>Position</code> values) without the need for ProtoFlux. <code>Progress</code> may be set to 0 to find the index of the minimum value as well.</translate>
</gallery>
 
== <translate><!--T:16--> See Also</translate> ==
 
[[Category:Components{{#translation:}}|Value Gradient Driver`1]]
[[Category:Generic Components{{#translation:}}|Value Gradient Driver`1]]
[[Category:Components With Nested Types{{#translation:}}|Value Gradient Driver`1]]
[[Category:Components:Transform:Drivers{{#translation:}}|Value Gradient Driver`1]]

Latest revision as of 23:40, 25 January 2025

Component image 
ValueGradientDriver component as seen in the Scene Inspector


The ValueGradientDriver component changes the value of the field defined in Target based on the items in the Points list and their Position in relation to the Progress value.

Fields

Fields
Name Type Description
persistent Bool Determines whether or not this item will be saved to the server.
UpdateOrder Int Controls the order in which this component is updated.
Enabled Bool Controls whether or not this component is enabled. Some components stop their functionality when this field is disabled, but some don't.
Progress Float Controls which items from the Points list will be used to drive the value of Target
Target field drive of T The field that this component will drive the value of
Interpolate Bool Controls whether or not this component will interpolate (or blend) between the nearest two Points to the current Progress value.
Points list of Point<T> A list of items indicating their Position (in relation to Progress), and a Value

Usage

Each point in the Points list has a Position field and Value field. The Position field is used for comparison with the component's Progress field, while the Value field is the value used for driving the field in Target.

When Interpolate is checked, the value stored in Target is linearly interpolated between the Values of the two points surrounding the current Progress. When unchecked, the output value is simply set to the Value of the closest point before the current Progress. The only exception to this is when no point exists before the current Progress, in which case the first point after the current Progress is used.

If two points have the same Position, then the point of greatest index takes priority if the value is not interpolated or if the positions are exactly equal to the current Progress. During interpolation, however, the point of least index takes priority.

Examples

See Also