From e3e65b951a469e8932cfe5adf585090dce8f623a Mon Sep 17 00:00:00 2001 From: meleki Date: Sat, 12 Sep 2026 21:21:24 +0200 Subject: [PATCH] Behaviors: lifecycle events On enable, On disable, On destroy (#42) --- Behaviors.md | 17 +++++++++++++++-- Concepts.md | 2 +- Containers.md | 3 ++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Behaviors.md b/Behaviors.md index 10272d9..817ea99 100644 --- a/Behaviors.md +++ b/Behaviors.md @@ -88,7 +88,7 @@ shown on the node and editable in the inspector. sideways slide of a Tetris piece, or a held arrow walking a menu. The browser's own key repeat is deliberately not used: its delay and rate are an operating-system setting, not a game's. Both 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`, +- **Node set** (`src/core/graph/nodes/`, one file per node): events `On start`, `On enable`, `On update`, `On disable`, `On destroy` (see *Lifecycle*), `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), `On animation finished`, `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), `Variables`, `Properties`, `Get position` (local and world), `Is enabled`, literals `Number`/`Text`/`Boolean`/`Texture`, `Add/Subtract/Multiply/Divide`, @@ -247,7 +247,20 @@ shown on the node and editable in the inspector. running the same behavior it is the one that produced last; in a loop, the last round. An output nothing has asked for yet shows nothing. The graph stays editable meanwhile: the interpreter reads the runtime copy's graph on every pulse, so an edit takes effect on the next frame and is discarded with - the run. A new `On start` node does not fire for a behavior that has already started. + the run. A new `On start` node does not fire for a behavior that has already started: `On start` + is asked once, when the instance comes to be (see *Lifecycle*). +- **Lifecycle**: a behavior gets its instance when it is effectively on — itself and every parent + switched on (and, in the editor run, "run in editor" set): at play start, when spawned, or the + moment a hidden screen is shown. The events come in this order: `On start` → `On enable` → + `On update` … → `On disable` → `On destroy`. `On start` runs once per instance. `On enable` runs + right after it and again every time the behavior comes back on; `On disable` runs in the frame it + goes off, a parent's switch included. Off, the instance is frozen, not gone: variables, timers and + states survive, and switching it on again is `On enable`, not `On start`. `On destroy` runs when + the object leaves the world — through `Destroy`, as a child of a destroyed object, and when the + game stops or restarts; a restart is therefore `On disable` → `On destroy` → (new world) `On start` + → `On enable`. The frame that destroys an object still runs to its end, the two farewell events + follow at the end of it; an object destroyed while off gets `On destroy` alone. Off and on again + within one frame is no edge: neither event fires. - **Runtime**: `BehaviorSystem` creates one `GraphInterpreter` per behavior entity; graphs only touch world entities. A runaway pulse throws (see *Loops* for the two limits) and stops play with a notice. diff --git a/Concepts.md b/Concepts.md index 5ddec8c..4cff445 100644 --- a/Concepts.md +++ b/Concepts.md @@ -4,7 +4,7 @@ | **Texture** | An uploaded image. Scenes, textures, animations and state machines are the four types that cannot be placed: a texture has no position, it is *worn* by a sprite through the ordinary property `texture`. See [Textures](Textures). | | **State machine** | A named set of **states**, edited as nodes in its own tab. A behavior puts it into a state with `Set state` and branches on it with `State branch`; each behavior instance keeps its own current state. See [State machines](State-machines). | | **Text** | An asset that draws a line of text (`text`, `fontSize`, `color`, `align`) — titles, HUD readouts, button labels. Its content is an ordinary property, so a `Properties` node of type Text with `text` switched to Set changes it while playing. | -| **Enabled** | Every placeable asset has the switch `enabled` (default on). A disabled object is not drawn, does not collide and its behavior does not run — **and neither does anything parented below it**. Switching one instance off is a normal override, which makes a container a *screen*: switch it on to show it, off to hide it. From a graph, `Properties` with `enabled` switched to Set does it, and `Is enabled` asks (including the parents). | +| **Enabled** | Every placeable asset has the switch `enabled` (default on). A disabled object is not drawn, does not collide and its behavior does not run — **and neither does anything parented below it**. Switching one instance off is a normal override, which makes a container a *screen*: switch it on to show it, off to hide it. From a graph, `Properties` with `enabled` switched to Set does it, and `Is enabled` asks (including the parents); a behavior hears the switch as `On enable` / `On disable`. | | **Scene object** | An asset placed into a scene: a link to the asset + a **position** (`x`, `y`, `z`) + sparse **overrides** of the asset's properties + an optional **parent** (another object of the scene). Scenes cannot be placed. | | **Container** | A reusable group ("prefab"): the asset holds a **template** of objects (asset link, local position, overrides, parent links) centred on its origin. Placing a container stores the container object **and nothing else** — its content is resolved from the template on every read, so a template edit reaches every instance at once. **Create container** turns the current selection into such an asset: the selected objects move into the template and the scene keeps one placed container at their centre (world positions unchanged). The template is edited in the **Container** tab (see [Containers](Containers)) or from an instance through **Apply to container**. | | **Selection** | One or more scene objects. Click selects, `Ctrl`/`Shift`-click adds/removes, dragging on empty scene space draws a rubber band (objects whose position lies inside are selected). Dragging a selected object moves the whole selection; `Delete` removes it; the inspector offers **Create container** and **Remove** for several objects. | diff --git a/Containers.md b/Containers.md index 1134401..3ea5225 100644 --- a/Containers.md +++ b/Containers.md @@ -56,7 +56,8 @@ switched on and off. It keeps working while it is off in one important way: `Obj still finds it, so a graph can switch it back on. A behavior inside a disabled screen has no interpreter yet — it gets one, and its `On start`, the moment the screen is switched on, which makes "the screen initialises itself when shown" the default. Its variables survive being -switched off and on again. A switched-off object is hidden in the Scene tab as well, so the +switched off and on again; every later show fires `On enable`, every hide `On disable` (see +[Behaviors](Behaviors), *Lifecycle*). A switched-off object is hidden in the Scene tab as well, so the editor shows what the game shows — selected, it keeps a faint outline, so where it sits is still visible, but it cannot be dragged. It stays listed in the hierarchy panel, which is where it is selected and switched back on.