Replace the five variable nodes with one Variables node
A single node now lists any number of variables. Every entry is an output that reads the current value whenever it is pulled; an entry switched to Set is also an input and is written when the flow arrives. Exec pins only exist while at least one entry writes, and all inputs are read before any write, so one node can swap two variables. Get/Set variable, Get/Set variables and Variable are gone. Old project files are converted on load: each old node becomes a Variables node with the same variables, edges and typed values. A written port without a typed value now shows the zero of its kind on the node body, matching what the inspector shows and what the run writes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
854ae2e756
commit
7c63c884ef
40 files changed
+895
-590
No files matched your search
@@ -99,16 +99,19 @@ shown on the node and editable in the inspector.
|
||||
|
||||
- **Variables** are the behavior's own property schema (`BehaviorAsset.variables`): they
|
||||
appear in the inspector, can be overridden per placed instance, and each running instance
|
||||
gets its own mutable copy. `Get variable` / `Set variable` read and write them, and are titled
|
||||
by the variable they name (*Get speed*, *Set speed*). `Variable` is both in one node, titled by the
|
||||
variable alone: its output can be read at any time – no flow has to reach it – and is read at the
|
||||
moment it is asked, so a read after a write sees the new value; an arriving flow writes its input.
|
||||
`count = count + 1` is one `Variable` node feeding its own output through an `Add` back into its
|
||||
input. Their plurals `Get variables` / `Set variables` do the same for several at once: their settings are a *list* of
|
||||
variables, one port per entry, so reading a handful is one node instead of a column of five. Those
|
||||
ports are picked from the behavior's variables rather than named, they take their type from the
|
||||
declaration, and renaming a variable carries them (and their edges) along. `Get properties` /
|
||||
`Set properties` do the same for the object they are handed: a built-in property (`width`,
|
||||
gets its own mutable copy. One node reads and writes them, `Variables`: its settings are a *list*
|
||||
of variables, and each one is an output that can be read at any time – no flow has to reach it –
|
||||
and is read at the moment it is asked, so a read after a write sees the new value. A variable
|
||||
switched to **Set** in the inspector is an input too, written when the flow arrives; the node has
|
||||
its flow pins only while at least one is. Unconnected and with nothing typed, it writes the zero
|
||||
of its kind (0, false, empty), and the node shows that value beside the name. All of them are written together, their inputs read
|
||||
first, so one node swaps two variables. `count = count + 1` is one `Variables` node feeding its
|
||||
own output through an `Add` back into its input. With a single variable the node is titled by it
|
||||
(*speed*). The ports are picked from the behavior's variables rather than named, they take their
|
||||
type from the declaration, and renaming a variable carries them (and their edges) along. Files
|
||||
from before this node still load: their `Get/Set variable(s)` and `Variable` nodes become
|
||||
`Variables` nodes that read or write the same variables. `Get properties` /
|
||||
`Set properties` pick their ports the same way, for the object they are handed: a built-in property (`width`,
|
||||
`color`, `align`, …) is picked from one list covering every object type, each entry named with
|
||||
its type (*Sprite width*, *Camera zoom* – a key several types share is there once per type), and
|
||||
keeps its own field and default – an unconnected `color` is a colour field starting white, shown
|
||||
@@ -160,8 +163,8 @@ shown on the node and editable in the inspector.
|
||||
rows stay off the node body while the delay is 0, so a plain key node keeps its single line.
|
||||
- **Node set** (`src/core/graph/nodes/`, one file per node): events `On start`, `On update`, `On key down/up/held`,
|
||||
`On timer`, `On collision enter/stay/exit`, `On click` (the mouse pressed on the owner – anywhere when it has none), `Start` · flow `Branch`, `Sequence`, `Repeat`, `Run behavior`, `End` · data `Self`, `Owner`, `Parent`, `Object by name`, `Name of`,
|
||||
`Is asset` (is this object an instance of asset X – how you tell what you collided with), `Get/Set
|
||||
variable`, `Variable`, `Get/Set variables`, `Get/Set property`, `Get/Set properties`, `Get position` (local and world), `Is enabled`, literals, `Add/Subtract/Multiply/Divide`,
|
||||
`Is asset` (is this object an instance of asset X – how you tell what you collided with),
|
||||
`Variables`, `Get/Set property`, `Get/Set properties`, `Get position` (local and world), `Is enabled`, literals, `Add/Subtract/Multiply/Divide`,
|
||||
`Min/Max/Abs/Sqrt/Clamp`, `Floor/Ceil/Round`, `Modulo`, `Random`, `Time`, `To text`, `To number`, `Join text`,
|
||||
`Substring`, `Find text`, `Equals`,
|
||||
lists `List` (a constant), `Fill` (one value repeated – how an empty board is made), `Count`,
|
||||
@@ -244,7 +247,7 @@ shown on the node and editable in the inspector.
|
||||
shape that could be hit, so it takes every click inside the camera frame instead (the
|
||||
`world x`/`world y` outputs say where) – that is the "click anywhere" listener.
|
||||
- **Idiomatic movement** (the demo's "Mover", five nodes): `On update → Move(Owner, dx = Axis
|
||||
input.x, dy = Axis input.y, scale = Get variable speed, dt = On update.dt)`.
|
||||
input.x, dy = Axis input.y, scale = speed, dt = On update.dt)`, `speed` being a `Variables` node.
|
||||
- **Idiomatic platformer** (the example game's "Player"): `On update` adds `gravity · dt` to a
|
||||
`vy` variable and moves the owner by `(axis.x · speed, vy)` with *Collide with solids* on;
|
||||
`blocked y` while falling means standing, so `vy` goes back to 0 and `onGround` becomes true;
|
||||
@@ -659,7 +662,7 @@ npm run check # typecheck + lint + format:check + tests, what CI would ru
|
||||
# code is lost (tail's is reported), so a red run reads as green
|
||||
npm run build # writes dist/ and regenerates index.html
|
||||
export GM_REMOTE=user@host # optional: run the browser elsewhere; see below
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 569 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 572 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 – a subset while working on one step
|
||||
./e2e.sh start [GM_STEPS] # the same run detached, see below
|
||||
./e2e.sh status # live progress, or the last run's result
|
||||
@@ -764,15 +767,13 @@ parallel variables copied back and forth, and each strand packs only the field i
|
||||
(`mergeStruct` keeps the rest). Reading a cell is `((shape · 4 + rot) · 4 + corner)` into that
|
||||
list instead of the same index doubled and read twice.
|
||||
|
||||
Where a step needs several variables at once, one `Get variables` / `Set variables` stands for the
|
||||
Where a step needs several variables at once, one `Variables` node stands for the
|
||||
lot: the call to `Next move` has **one node at each side** of it rather than five, and the master
|
||||
graph is **44 nodes / 64 edges** where the same game in single nodes was 69 / 76. Inside `Next
|
||||
move` each strand writes its whole answer – the candidate, what kind of move it was and the wish
|
||||
it used up – in one node rather than three to five, which is **30 nodes** against 40. Two things
|
||||
bound how far such a node may reach: a data node answers once per pulse and keeps that answer, so
|
||||
a `Get variables` must not straddle a write of one of its variables (which is why the board is
|
||||
read a second time after the lines were cleared), and a `Set variables` reads all its inputs
|
||||
before it writes any, so none of them may come from a variable it writes.
|
||||
it used up – in one node rather than three to five, which is **30 nodes** against 40. A writing
|
||||
node reads all its inputs before it writes any, so an input fed from a variable the same node
|
||||
writes sees the value from before.
|
||||
|
||||
It is **ten behaviors**, not one graph. `Tetris` owns the state and does none of the work: each
|
||||
step of a frame is a behavior of its own, called as a node – `Spawn piece`, `Next move`, `Fits`,
|
||||
|
||||
Reference in new issue
Block a user