Move Keep from the Run behavior node to each variable (#229)

- Behaviors: the point "Keep" describes the switch in the variable
  row. New variables start with it on, existing ones off.
- State-machines: back to the text before #229. Local machines in a
  called behavior start empty on every call.
admin committed 2026-09-25 15:51:08 +02:00
1 parent 151ea288ab
commit f436f6d5a9
2 files changed
+15 -12

No files matched your search

+11 -8
@@ -213,14 +213,17 @@ shown on the node and editable in the inspector.
variable defaults, so values travel in and out through the ports and nothing else. That makes a
call repeatable and keeps a nested behavior free of hidden state. A behavior that would run
itself raises an error instead of looping; there is one start and one end node per behavior.
- **Keep state** (a checkbox on the calling node, off by default): the nested behavior then picks
up its variables and its local state machines where the last call **from this node, on this
object** left them. Two call nodes running the same behavior keep a state each, and so do two
objects running the same graph; a kept call inside a kept call has one per outer node. It follows
today's declarations: a variable added since starts at its default, a removed one is dropped, and
one whose kind changed starts over. The state lives as long as the object does in the run and is
never saved. For state shared between objects, use a Variables asset or a behavior object in the
scene (see *Cross-object state* below).
- **Keep** (a switch on each variable of the called behavior, in its inspector): a kept variable
picks up where the last call **from this node, on this object** left it; the others start at
their default every call. A variable added to a behavior starts out kept, and one from a project
saved before the switch existed starts out not kept, so older projects run as they did. Two call
nodes running the same behavior keep a state each, and so do two objects running the same graph;
a call inside a call has one per outer node. It follows today's declarations: a variable added
since starts at its default, a removed one is dropped, and one whose kind changed starts over.
The kept value lives as long as the object does in the run and is never saved. Local state
machines of the called behavior are not kept, they start in no state every call. For state
shared between objects, use a Variables asset or a behavior object in the scene (see
*Cross-object state* below).
Three ways in and out of a call: **drag** a behavior out of the asset panel onto the graph and it
lands as a call where you let go; **double-click** a call node to open the graph it runs. The
way down stays above the graph as a **breadcrumb** (`Game > Move > Other`): click a crumb to go
+4 -4
@@ -146,8 +146,8 @@ The rules, all of them worth knowing before wiring a graph on them:
whose events keep moving the machine stops the run with an endless-loop error, like the step limit.
- Who hears it follows the **scope**: a local machine is heard by the instance that moved it alone,
a global one by **every** instance with a matching event node — which is the point of sharing a
state. A move a nested `Run behavior` makes to a *local* machine is not reported, and it dies
with the call unless the call node has **Keep state** on (see *Behaviors*); a move it makes to a
state. A move a nested `Run behavior` makes to a *local* machine dies with the call and is not
reported, even where the called behavior keeps variables (see *Behaviors*); a move it makes to a
global one is a move like any other.
## The current state while playing
@@ -162,8 +162,8 @@ gone the moment the run stops. Play repaints the tab the way it repaints the Beh
**A local machine's current state is the behavior instance's own**, kept beside its variables
(`NodeContext.states`, machine id → state id): two crates running the same behavior are in
states of their own, and a behavior run through `Run behavior` starts in no state, as it starts
with fresh variables, unless the call keeps its state. A **global** one is kept for the run instead (`SharedState.states`, built
states of their own, and a behavior run through `Run behavior` starts in no state,
and again with every call. A **global** one is kept for the run instead (`SharedState.states`, built
once per run in `core/graph/sharedState.ts`) and every instance reads and moves that one — which
bag a node touches is decided by the machine's scope, not by the node (`stateBag`). Neither
survives a stop: both begin the next Play at the start state again, or in no state where there is