UnigineScript
The Language
Core Library
Engine Library
Node-Related Classes
GUI-Related Classes
Plugins Library
Samples
C++ API
API Reference
Integration Samples
Usage Examples
C++ Plugins
Content Creation
Materials
Unigine Material Library
Tutorials

Unigine::Schemer

Schemer is a visual scripting system that allows a developer to create complex sequences of gameplay events without having to script them manually. This way the artists can add interactivity to the world without the help of a programmer. By connecting paths in a flow graph, it is possible to script cutscenes, switches, timers, changes in lighting and much more.
Schemer (as well as Skinner) can either be loaded inside Unigine window or in the external widgets.

Schemer scripts can be found under data/core/systems/schemer folder.

Schemer graph

Schemer graph editor

Overview

Schemer flow graph consists of the following entities:

  • Blocks are the main entities of the Schemer. They describe events, operations or variables of different types. The gameplay programmers code these actions depending on the project needs and make them available to be used in the Schemer by artists. For example, a block can describe the behavior of the game object, for example, the explosion sequence of a game vehicle.
    There is also a number of predefined blocks that perform various arithmetic operations, print a message, etc.
  • Nodes are Block units that form the graph sequence; they can be dragged around the graph canvas. That is, while Block is the type of the node that determines what action to do, a node is a block that has been added to the graph to perform this action, given the exact input data. Nodes of the same Block differ in their variables and states.
  • Nodes are connected together by Joints. Joints can be of two types:
    • Paths are rendered in white. They control the sequence of executing nodes when the Schemer script is run. That is, by moving along the path joints we could trace how the graph is unrolling starting from each possible entry point (the first nodes of the script) and what are the next triggered nodes.
    • Links are rendered in green. They simply connect nodes that store values and do not perform anything by themselves.
  • The point of connection is called an Anchor. Anchors can be of different shapes (round for output paths from a node and square for input paths into a node).
  • Schemer editor is a canvas on which the created graph is drawn. It uses Unigine::Widgets::Graph classes for drawing.

How To Use Schemer Graph

To create a graph, drag the blocks onto editor canvas.

  1. The first node to start the graph with should always be schemer.entry. The name of this entry point is specified in the world script. By default (in Schemer sample), main name should be specified.
  2. Put the cursor over the Output anchor and drag the joint to the Input anchor of the next node. Paths that connect Output and Input anchors control a sequence of executing a graph.
  3. Values that nodes operate on are marked in green. The value on the right side of a node is an output value that contains the result of the operation performed by this node. The value on the right side is an input value. Connect two values to pass a value from one node to another.
Drag the node with the SHIFT button pressed to clone the block. To zoom in or out, press and drag the right mouse button.

Schemer graph

Creating Schemer graph

After the Schemer graph has been created or modified, click Run button. A script will be generated out of the graph, compiled on-the-fly and run.

You can also save the created script into *.script file to be loaded and edited later or executed at runtime.

Blocks

Inside blocks are functions or snippets of UnigineSript code. The resulting script created from a Schemer graph is made up of code snippets from all blocks put together one after another. When blocks are processed, separate namespaces are created for each of the block to avoid name collisions.

Just like any other script, a block has a number of functions to control its behavior:

  • init is for code executed on the Schemer script initialization. It can be used to initialize heavy resources: for example, Skinner loads animations and creates buffers in the init code.
  • shutdown is for code executed on the Schemer script shutdown.
    Both init() and shutdown() code snippets do not depend on the graph execution sequence. All blocks will be initialized or shout down at once (see the details).
  • update is for code executed when the graph is executed and it is the turn for node with the current block to be activated.
  • common is for functions and variables that should have a global scope inside of the block.

Any of these functions inside of the block can be omitted, if necessary.

Blocks File Syntax

Blocks are described in a *.blocks file of XML format. For example, the default blocks are contained in the data/core/systems/schemer/blocks/schemer.blocks.

Besides functions to execute, a block also describes its joints:

  • Input and output paths (input_path and output_path) to connect a node with this block to other nodes.
  • Input and output links (input_link and output_link) are used to receive variables from, and pass them to other nodes.
Source code (XML)
<?xml version="1.0" encoding="utf-8"?>
<blocks version="1.00">
	<block type="schemer.message">
		<input_path>input</input_path>
		<output_path>output</output_path>
		<input_link>value</input_link>
		<init>log.message("schemer.message: block is initialized with a script\n");</init>
		<shutdown>log.message("schemer.message: block is shut down with a script\n");</init>
		<update>log.message("schemer.message: %s\n",typeinfo(value));</update>
	</block>
</blocks>

If the code should contain characters like ">" or "&" that are illegal in XML elements, use CDATA to indicate a section ignored by the parser.

Source code (XML)
<update><![CDATA[
	if(a > b) goto output_gt;
	if(a < b) goto output_lt;
	goto output_eq;
]]></update>

The available attributes for joints (both paths and links) are as follows:

  • label — text at the anchor point
  • align — position of the anchor point on the specified side of the node. Possible values are left, right, bottom.
  • value — the default value to use.
  • mask — bit mask for connecting only the anchors with a matching mask. For a joint to be created between two anchors, at least one bit of masks should match.

Customize Basic Blocks

If you want to customize any of the available blocks, you need to edit data/core/systems/schemer/blocks/schemer.blocks. There, you can modify init, update or shutdown functions written in UnigineSript, add anchors to connect to other nodes, etc.

Adding a Custom Blocks File

If you want to expand the list of predefined blocks, you can add custom blocks files. New blocks can be loaded via loadBlocks(string name) function in the Schemer constructor (data/core/systems/schemer/schemer.h file).

Available Schemer Blocks

The following blocks are the basic Schemer blocks defined in the data/core/systems/schemer/schemer_blocks.h script.

schemer.entry This is a start-up point for running a graph. There can be multiple entry points in one graph. What point to use to start the graph is defined from the world script. It has the following parameter:
  • Name — the name of the entry point. This name should be hard-coded in the world script using SchemerScript::update() function; otherwise the graph cannot be run. (See the details how to run the Schemer below).
schemer.input Passes the variable to the next Schemer node.
  • Name — the passed variable.
schemer.output Stores the variable received from the previous Schemer node.
  • Name — the received variable.
schemer.boolean Set the true (checked) or false (unchecked) value.
schemer.constant Sets a variable.
  • Value — the type of the variable (int, float, string, vec3 or vec4).
schemer.file Stores the file name.
  • File — path to the file.

The following blocks are the predefined Schemer blocks loaded from data/core/systems/schemer/blocks/schemer.blocks file.

schemer.abs Outputs the absolute value of the input value. For example, if input value is -2, the output value will be 2.
  • value — input value.
  • abs — output absolute value.
schemer.acos Outputs the arc cosine of the value. It is the inverse cosine function, which means that a == cos(acos(a)) for every value of a that is within acos()'s range.
  • value — input value.
  • acos — arc cosine of the value.
schemer.add Adds values. The resulting value = a + b.
  • a, b — input values.
  • a + b — output sum value.
schemer.and Performs a boolean logical AND on input values. Evaluates if both operands are true; otherwise, false is output.
  • a, b — input operands.
  • a && b — output if both operands are true.
  • else — output if at least one of the operands is false.
schemer.asin Outputs the arc sine of the value. asin() is the inverse sine function, which means that a == sin(asin(a)) for every value of a that is within asin()'s range.
  • value — input value.
  • asin — arc sine of the value.
schemer.atan Outputs the arc tangent of the value. atan() is the inverse tangent function, which means that a == tan(atan(a)) for every value of a that is within atan()'s range.
  • value — input value.
  • atan — arc sine of the value.
schemer.atan2 Outputs the arc tangent of two input values. It is similar to calculating the arc tangent of y / x, except that the signs of both arguments are used to determine the quadrant of the result.
  • value — input value.
  • atan2 — result in radians, which is between -PI and PI (inclusive).
schemer.band Performs a bitwise AND on two integers. It compares each bit of its first operand to the corresponding bit of the second operand. Each bit in the result is 1 only if both corresponding bits in the two input operands are 1.
  • a, b — input operands.
  • a & b — output used if the resulting value is equal to 0.
  • else — output used in case of non-zero result.
schemer.bor Performs a bitwise inclusive OR on two integers. It compares each bit of its first operand to the corresponding bit of the second operand. If both of the corresponding bits in the two input operands are 0, the result of that bit in the result is 0; otherwise, if either of the bits is 1 the result is 1.
  • a, b — input operands.
  • a | b — output used if the resulting value is equal to 0.
  • else — output used in case of non-zero result.
schemer.bxor Performs a bitwise exclusive OR on two integers. It compares each bit of its first operand to the corresponding bit of the second operand. If both bits are 1 or both bits are 0, the corresponding bit of the result is set to 0. Otherwise, the corresponding result bit is set to 1.
  • a, b — input operands.
  • a ^ b — output used if the resulting value is equal to 0.
  • else — output used in case of non-zero result.
schemer.ceil Calculates the smallest integral value that is not less than input value. For vectors values are obtained per component. For example, if input value is 2.4, the output value will be 3.
  • value — input value.
  • ceil - output integral value.
schemer.clamp Clamps a value within the specified min and max limits.
  • value — input value.
  • min - minimum possible value. The default is 0.
  • max - maximum possible value. The default is 1.
  • clamp - clamped input value.
schemer.clock Returns the time in seconds passed from the application start-up.
  • clock — time.
schemer.copy Copies an input variable to be passed to further nodes. A node can copy its variable only to the next node that it triggers. This node can serve as a temporary buffer to store the variable between node run-times.
  • value (at the left) — input value.
  • value (at the right) — the same output value.
schemer.cos Outputs the cosine of the value.
  • value — input value.
  • cos — cosine of the value.
schemer.counter Increments value of the counter. The default counter value is 0 (changed to 1 when the counter node is triggered).
  • value — the incremented value.
  • clear - resets the input counter to 0.
  • output (at the bottom) - output path in case the counter was reset.
schemer.cross Outputs cross product of two input vectors.
  • a, b — input vectors.
  • cross — cross product of vectors.
schemer.delay Triggers an event (a next node) after the specified interval has passed. (See also schemer.timer for a constant trigger.)
  • time (1) — the duration of the pause before generating an event. The default is 1 second.
  • output - the immediate output.
  • delay - the output after the specified time has passed.
schemer.div Divides the values. The resulting value = a / b.
  • a, b — input values.
  • a / b — output division result.
schemer.dot Outputs dot product of two input vectors.
  • a, b — input vectors.
  • dot — dot product of vectors.
schemer.dot3 Outputs dot product only of three components of vectors. In case an argument is a four-component vector, its w component is ignored.
  • a, b — input vectors.
  • dot — dot product of vectors.
schemer.event Generates an event if the input value has changed. Otherwise, output exit is used.
  • value — input value. It can store the state of some parameter.
  • output — output used by unchanging value.
  • event — output used when the value has changed.
schemer.exp Calculates the exponent of the value.
  • value — input value.
  • exp — exponent of the value.
schemer.floor Rounds an input value down to the nearest integer. For vectors values are obtained per component. For example, if input value is 2.4, the output value will be 2.
  • value — input value.
  • floor — rounded value.
schemer.frac Calculates the a fraction part of fraction part of the input value. For vectors values are obtained per component. For example, if input value is 2.4, the output value will be 0.4.
  • value — input value.
  • frac — fraction part value.
schemer.if Compares two input values and uses different outputs depending on the results of comparison.
  • a, b — input values.
  • a > b — output used if a is greater than b.
  • a < b — output used if a is less than b.
  • a = b — output used if a is equal to b.
schemer.length Calculates the length of a vector.
  • value — input value.
  • length — vector length value.
schemer.length2 Calculates the square length of a vector.
  • value — input value.
  • length2 — square vector length value.
schemer.lerp Calculates the linear interpolation between two values according to the following formula:
a + (b - a) * k
  • a, b — input values.
  • k — interpolation coefficient.
  • lerp — interpolated value.
schemer.log Calculates a natural logarithm of the value.
  • value — input value.
  • log — logarithm of the value.
schemer.log10 Calculates base-10 logarithm of the value.
  • value — input value.
  • log — logarithm of the value.
schemer.loop Repeats the triggering of the another node for a certain number of times.
  • from (0) — this value will be subtracted from the to value to calculate the number of loops. The default is 0 (to) value.
  • to — the number of loops, unless from value is specified.
  • step — increment step for the loop counter.
  • output value — the number of executed loops (including the 0 one).
  • output — the next node to be triggered after the loops over.
schemer.mad Multiplies the first two input values and adds the third one to the result. The resulting value = a * b + c.
  • a, b, c — input values.
  • a * b + c — output result.
schemer.mat4 Constructor for a matrix (mat4).
  • rot (quat(0,0,1,0)) — input quaternion that defines rotation. The default is quat(0,0,1,0).
  • pos (vec3(0,0,0)) — input vector that defines position. The default is vec3(0,0,0).
  • mat4 — output matrix.
schemer.max Finds the greatest value.
  • a, b — input values to compare.
  • max — the greatest value.
schemer.message Prints a message into the console in the format schemer.message: <vale_type>: "<value>".
  • value — string with message in format "<message>".
schemer.min Finds the smallest value.
  • a, b — input values to compare.
  • min — the smallest value.
schemer.mod Performs a modulo operation (calculates the remainder after division of one value by another).
  • a, b — input values to compare.
  • a % b — output remainder.
schemer.mul Multiplies two input values. The resulting value = a * b.
  • a, b — input values to multiply.
  • a * b — output multiplication result.
schemer.normalize Normalizes a vector.
  • value — input vector.
  • normalize — normalized vector.
schemer.or Performs boolean logical OR on input values. This operation results true if both operands are true and false if both are false.
  • a, b — input operands.
  • a || b — output if both operands are true.
  • else — output if both operands are false.
schemer.pow Calculates the exponential expression.
  • a — base.
  • b — power.
  • pow — base (a) raised to the power (b) of the exp.
schemer.quat Constructor for a quaternion (quat).
  • axis (vec3(0,0,1)) — axis of rotation. The default is vec3(0,0,1).
  • angle (0) — angle of rotation. The default is 0 degrees.
  • quat — output quaternion.
schemer.rand Generates a random integer value.
  • from (0) — the smallest possible value. The default is 0.
  • from (1024) — the greatest possible value. The default is 1024.
schemer.rcp Inverses a value. For vectors values are obtained per component. The result = 1.0 / value.
  • value — input value.
  • rcp — reciprocal of the value.
schemer.rsqrt Inverted square root. The result is one divided by the square root of value.
  • value — input value.
  • rsqrt — inverted square root of the value.
schemer.select Allows to switch between two output values depending on what trigger value has entered the node. If the trigger value does not match any of the cases (i.e. 0 or 1), the default value is output.
  • value (at the left) — input trigger value.
  • case 0 — value to be output if the trigger is equal to 0.
  • case 1 — value to be output if the trigger is equal to 1.
  • default — value to be output if the trigger is not equal to 0 or 1.
  • value (at the right) — selected output value.
schemer.select3 Allows to switch between three output values depending on what trigger value has entered the node. If the trigger value does not match any of the cases (i.e. 0, 1 or 2), the default value is output.
  • value (at the left) — input trigger value.
  • case 0 — value to be output if the trigger is equal to 0.
  • case 1 — value to be output if the trigger is equal to 1.
  • case 2 — value to be output if the trigger is equal to 2.
  • default — value to be output if the trigger is not equal to 0, 1 or 2.
  • value (at the right) — selected output value.
schemer.select4 Allows to switch between four output values depending on what trigger value has entered the node. If the trigger value does not match any of the cases (i.e. 0, 1, 2 or 3), the default value is output.
  • value (at the left) — input trigger value.
  • case 0 — value to be output if the trigger is equal to 0.
  • case 1 — value to be output if the trigger is equal to 1.
  • case 2 — value to be output if the trigger is equal to 2.
  • case 3 — value to be output if the trigger is equal to 3.
  • default — value to be output if the trigger is not equal to 0, 1, 2 or 3.
  • value (at the right) — selected output value.
schemer.select5 Allows to switch between five output values depending on what trigger value has entered the node. If the trigger value does not match any of the cases (i.e. 0, 1, 2, 3 or 4), the default value is output.
  • value (at the left) — input trigger value.
  • case 0 — value to be output if the trigger is equal to 0.
  • case 1 — value to be output if the trigger is equal to 1.
  • case 2 — value to be output if the trigger is equal to 2.
  • case 3 — value to be output if the trigger is equal to 3.
  • case 4 — value to be output if the trigger is equal to 4.
  • default — value to be output if the trigger is not equal to 0, 1, 2, 3 or 4.
  • value (at the right) — selected output value.
schemer.sign Outputs the sign of the input value. If a positive value or 0 is provided, the output result will be equal to 1. If a negative value is input, the result will be -1. For vectors values are obtained per component.
  • value — input trigger value.
  • sign — sign value (1.0 if arg >= 0.0; -1.0 if arg < 0.0).
schemer.sin Outputs the sine of the value.
  • value — input value.
  • sin — sine of the value.
schemer.sqrt Outputs the square root of the value.
  • value — input value.
  • sqrt — square root of the value.
schemer.state State machine with two states. It allows to create different reactions to the same input trigger.
The state machine automatically choses the output path depending on its stored state. By default the state is equal to 0. Meaning, if the node is entered using input anchor, it will exit using out 0. When a node is entered via in 1, the machine will change its state to 1 and exit using out 1. Next time the node is triggered via input, it will automatically exit via out 1 again, as the state stores its last changed value.
  • input — basic input. The output path will depend on the stored state.
  • in 0 — sets the state of the machine to 0.
  • in 1 — sets the state of the machine to 1.
  • out 0 — the output automatically used if state is equal to 0.
  • out 1 — the output automatically used if state is equal to 1.
  • state — the current state value (0 or 1).
schemer.state3 State machine with three states. It allows to create different reactions to the same input trigger.
The state machine automatically choses the output path depending on its stored state. By default the state is equal to 0. Meaning, if the node is entered using input anchor, it will exit using out 0. When a node is entered via in 2, the machine will change its state to 2 and exit using out 2. Next time the node is triggered via input, it will automatically exit via out 2 again, as the state stores its last changed value.
  • input — basic input. The output path will depend on the stored state.
  • in 0 — sets the state of the machine to 0.
  • in 1 — sets the state of the machine to 1.
  • in 2 — sets the state of the machine to 2.
  • out 0 — the output automatically used if state is equal to 0.
  • out 1 — the output automatically used if state is equal to 1.
  • out 2 — the output automatically used if state is equal to 2.
  • state — the current state value (from 0 to 2).
schemer.state4 State machine with four states. It allows to create different reactions to the same input trigger.
The state machine automatically choses the output path depending on its stored state. By default the state is equal to 0. Meaning, if the node is entered using input anchor, it will exit using out 0. When a node is entered via in 2, the machine will change its state to 2 and exit using out 2. Next time the node is triggered via input, it will automatically exit via out 2 again, as the state stores its last changed value.
  • input — basic input. The output path will depend on the stored state.
  • in 0 — sets the state of the machine to 0.
  • in 1 — sets the state of the machine to 1.
  • in 2 — sets the state of the machine to 2.
  • in 3 — sets the state of the machine to 3.
  • out 0 — the output automatically used if state is equal to 0.
  • out 1 — the output automatically used if state is equal to 1.
  • out 2 — the output automatically used if state is equal to 2.
  • out 3 — the output automatically used if state is equal to 3.
  • state — the current state value (from 0 to 3).
schemer.state5 State machine with five states. It allows to create different reactions to the same input trigger.
The state machine automatically choses the output path depending on its stored state. By default the state is equal to 0. Meaning, if the node is entered using input anchor, it will exit using out 0. When a node is entered via in 2, the machine will change its state to 2 and exit using out 2. Next time the node is triggered via input, it will automatically exit via out 2 again, as the state stores its last changed value.
  • input — basic input. The output path will depend on the stored state.
  • in 0 — sets the state of the machine to 0.
  • in 1 — sets the state of the machine to 1.
  • in 2 — sets the state of the machine to 2.
  • in 3 — sets the state of the machine to 3.
  • in 4 — sets the state of the machine to 4.
  • out 0 — the output automatically used if state is equal to 0.
  • out 1 — the output automatically used if state is equal to 1.
  • out 2 — the output automatically used if state is equal to 2.
  • out 3 — the output automatically used if state is equal to 3.
  • out 3 — the output automatically used if state is equal to 4.
  • state — the current state value (from 0 to 4).
schemer.sub Subtracts one input value from another. The resulting value = a - b.
  • a, b — input values to multiply.
  • a * b — output subtraction result.
schemer.switch Allows to switch between two output variants depending on the input value.
  • value — value that controls what output variant is used.
  • case 0 — the first output variant used if input value is equal to 0.
  • case 1 — the second output variant used if input value is equal to 1.
  • default — the output used when the input value does not match 1 or 2.
schemer.switch3 Allows to switch between three output variants depending on the input value.
  • value — value that controls what output variant is used.
  • case 0 — the first output variant used if input value is equal to 0.
  • case 1 — the second output variant used if input value is equal to 1.
  • case 2 — the third output variant used if input value is equal to 2.
  • default — the output used when the input value does not match numbers from 0 to 2.
schemer.switch4 Allows to switch between four output variants depending on the input value.
  • value — value that controls what output variant is used.
  • case 0 — the first output variant used if input value is equal to 0.
  • case 1 — the second output variant used if input value is equal to 1.
  • case 2 — the third output variant used if input value is equal to 2.
  • case 3 — the fourth output variant used if input value is equal to 3.
  • default — the output used when the input value does not match numbers from 0 to 3.
schemer.switch5 Allows to switch between five output variants depending on the input value.
  • value — value that controls what output variant is used.
  • case 0 — the first output variant used if input value is equal to 0.
  • case 1 — the second output variant used if input value is equal to 1.
  • case 2 — the third output variant used if input value is equal to 2.
  • case 3 — the fourth output variant used if input value is equal to 3.
  • case 4 — the fifth output variant used if input value is equal to 4.
  • default — the output used when the input value does not match numbers from 0 to 4.
schemer.tan Outputs the tangent of the value.
  • value — input value.
  • tan — tangent of the value.
schemer.time Returns the current system time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds.
  • time — output time.
schemer.timer Triggers other nodes in a specified intervals until stopped. (See also schemer.delay for one-time trigger.)
  • time (1) — the time interval to trigger events. the default is 1 second.
  • output (at the right) — the immediate output.
  • timer — the output used to start triggering events.
  • stop — the input used to stop the timer from generating more events.
  • output (at the bottom) — output used when the timer has been stopped.
schemer.value Allows to set a stored constant value to a number of other nodes.
  • value — value to be output.
schemer.vec3 Constructor for a three component vector (vec3).
  • x (0) — X component of the vector. The default is 0.
  • y (0) — Y component of the vector. The default is 0.
  • z (0) — Z component of the vector. The default is 0.
  • vec3 — output vector.
schemer.vec4 Constructor for a four component vector (vec4).
  • x (0) — X component of the vector. The default is 0.
  • y (0) — Y component of the vector. The default is 0.
  • z (0) — Z component of the vector. The default is 0.
  • w (0) — W component of the vector. The default is 0.
  • vec4 — output vector.
schemer.xyz Allows to access and output X, Y and Z elements of a vector separately. This node can take vec3, vec4, quat and mat4 (if necessary).
  • value — input value of the supported type.
  • x — output X element.
  • Y — output Y element.
  • z — output Z element.
schemer.xyzw Allows to access and output X, Y, Z and W elements of a vector separately. This node can take vec4, quat and mat4 (if necessary).
  • value — input value of the supported type.
  • x — output X element.
  • Y — output Y element.
  • z — output Z element.
  • w — output W element.

How to Run Schemer Script

To run the Schemer from the script (here, without a visual editor), you need to add the code as in the following example. update() function of the script compiled from a graph. It will execute all its nodes one by one in the specified order.

Source code (UnigineScript)
#include <core/scripts/utils.h>
#include <core/systems/schemer/schemer.h>

/*
 */
int init() {

	// Use Schemer namespace.
	using Unigine::Schemer;

	// Create a Schemer.
	Schemer schemer = new Schemer();

	// Create Schemer script that will compile an executable script out of the graph.
	SchemerScript script = new SchemerScript(schemer);
	
	// Load the previously created a graph.
	script.load("samples/schemer/scripts/delay.script");
	
	// Compile the loaded graph into a script.
	script.compile();
	
	// Run <init></init> code of all blocks used in the script. Here,
	// constants in schemer.constant blocks are initialized. This line could be omitted,
	// if not necessary.
	script.init();
	
	// Run the graph.
	script.update(script.getEntryID("main"));

	return 1;
}
Last update: 2017-07-03