Skip to content
Vilanel

Node graph

Wiring up game logic and building an animation blend tree use the same canvas, the same file format and the same runtime. Only the palette of available nodes differs.

The canvas is shared, the nodes are not

Panning, zooming, the grid, box selection and dragging several nodes at once are the same job whatever the nodes represent, so they are written once.

What stays specific to each editor is what its nodes are and how they draw. Building a second editor would have meant a second copy of everything in the first list, which is where two editors start behaving differently for no reason anyone chose.

The dividing line turned out to be clean. Dragging a wire from one connection point to another stayed with the logic editor, because animation state machines join whole states rather than individual inputs. Had the shared canvas kept track of which connection point a drag started from, half of what uses it would have had nothing to put there.

Connection types

Twelve types, each with a colour. The type is read by colour before it is read by label:

TypeWhat it carries
ExecThe order things happen in
BoolTrue or false
IntWhole numbers
FloatDecimal numbers
StringText
VectorPositions and directions
ColorA colour
ObjectA reference to an object or an asset
StructA group of values you defined
TextureAn image
EventSomething that can be triggered
WildcardTakes the type of whatever you connect

Order-of-execution connections are triangles. Value connections are circles. Colour alone is never enough, and a graph is the worst place to rely on it, because a red connection and a green one sit inches apart. The shape difference means the distinction does not depend on being able to tell them apart.

Animation state machines

A state machine is built from the same nodes and wires as everything else, so it inherited the canvas, saving, undo and the properties panel without any of them being written again.

Why it is not built from the existing nodes

The obvious way to say "play this animation or that one" with what already existed is a chain of either-or nodes. That does not work, and the reason is worth writing down.

Those nodes calculate both of their inputs before choosing between them. Twenty states means twenty animations sampled every frame, nineteen of which are thrown away.

The fix could not be a new node, because a node's inputs are always calculated before the node itself runs. It had to happen when the graph is compiled: the work for each state is only generated inside the branch that runs when that state is active. The test measures it rather than asserting it. Two states, one animation sampled.

Transitions are nodes too

A transition has a condition and a name, and something with properties needs somewhere to show them. Making it a node means it gets selection and the properties panel from the canvas everything else already uses.

A state can have several ways out

Which no other kind of node allows. Elsewhere, two order-of-execution wires leaving one point have no defined order, so the editor prevents it. But a state's outgoing wires are not "then do this", they are "these are the ways out of here", and they are considered in the order you made them. A state with three ways out is the ordinary case.

Blending between states, and where the timer lives

The graph itself cannot track how far through a blend it is, and it should not. The same graph running on two characters has two blends in progress at once, so the timer belongs to the character rather than to the graph.

So the split is: the compiled graph records which state is current, which one it is coming from, and how long the blend should take. The character owns the clock, and while a blend is running it evaluates both states and mixes the results.

How they are mixed is chosen in the graph rather than decided by the compiler. An empty choice means an instant cut, in which case none of the blending work is generated at all. That is what keeps the underlying mechanism honest: it selects between things without knowing what they are, which is why the tests for it use plain numbers rather than animations.

The cost is visible and bounded: one animation normally, three during a blend, back to one when it finishes.

Errors appear on the node

A required connection left empty puts a red border on the node itself.

An error that only appears in the log requires you to notice a line, read it, and go looking for the node it names. Putting the error where the mistake is removes all three steps.