Node is the primitive of Ignis.
Nodes are constructed in trees, inheriting the properties and transforms of their ancestors.
A node declares its behavior and children in build(), which runs whenever the node enters a scene. Per-frame logic is registered with
tick.
@override
void build() {
super.build();
final square = add(
ShapeNode(
shape: .square(40),
anchor: .center,
paint: Paint()..color = Colors.orange,
),
);
tick((dt) {
square.angle += pi / 4 * dt;
});
}
super.build() is required. Skipping it drops whatever the superclass declared.
Never make build() async. An asynchronous build breaks engine invariants in multiple, devastating ways.
For a complete list of available nodes, see Built-in Nodes.
Building#
Nodes install behavior in the build method, called whenever the node is mounted to a scene.
Behavior is composed from a mere three primitives: tick, draw, and trash. Each primitive takes a callback and registers it for execution. This apparently innocuous pattern simultaneously enables
Locality of Behavior and Live Reload.
tick and draw callbacks are executed first-in-first-out, like a queue. trash
callbacks are executed first-in-last-out, like a stack.
For tick and draw, a parent's callbacks run before their children's callbacks. For
draw, this means parents always render beneath their children.
tick, draw, and trash may only be called inside
build.
Ticking#
tick registers a callback to run every frame of the game loop. dt is the frame time in seconds. See
Time.
tick((dt) {
position.addScaled(velocity, dt);
});
Drawing#
draw registers a callback to paint something to the canvas. canvas is always in the node's own coordinate space. The origin is wherever the node exists in the tree.
draw((canvas) {
canvas.drawCircle(.zero, radius, paint);
});
There is an additional drawing primitive, debugDraw, available for visual debugging purposes. See
Debugging.
Trashing#
trash registers a callback to run when the node is unmounted or rebuilt. It is most commonly used to clean up resources created for that node.
final painter = TextPainter(text: span);
trash(painter.dispose);
Enabled#
Nodes have an enabled flag, allowing you to dynamically activate or deactivate them in the tree. When disabled, the node will no longer tick or draw.
red.enabled = false;
taps.onTap(() {
red.enabled = !red.enabled;
});
Use the enabled flag to avoid micromanaging nodes that only need to run intermittently.
Priority#
A node's children are sorted by priority. Priority dictates the order in which children of the same node are processed, covering updating and rendering.
A node's default priority is 0. With this default, children are processed in the order in which they are
added.
With priority, you can manually adjust this order. Consider the following examples:
By default, the two shapes are rendered in the order in which they are added.
add(circle);
add(box);
Giving the first shape a higher priority causes it to be rendered on top, despite the second having been added later.
add(circle..priority = 1);
add(box);
However, priority only applies to siblings of the same node. A child is always processed after its parent, and no amount of
priority can change this.
add(box..priority = 1000);
box.add(circle);
Signals#
Node comes with three signals, which makes them available on every node in the engine.
onMountis emitted when entering a scene.onUnmountis emitted when exiting a scene.-
onSceneResizeis emitted when entering a scene, and again whenever the scene changes size.
Signals watched inside build do not need to be unsubscribed from. See Signals.
