diff --git a/Behaviors.md b/Behaviors.md index a965252..850ed94 100644 --- a/Behaviors.md +++ b/Behaviors.md @@ -39,25 +39,26 @@ playing use the same two words. type as a setting row (*Type: Sprite*, plus *Behavior: Game* under that type). Textures and scenes are no type here: they are not objects in a running game. A variable is a **number, a text, a yes/no, a colour, a texture, a state machine, an asset, an object, a list or a struct**; a list declares **nothing** about its items — - each one is a number, a text, a yes/no, a colour, a texture, a state machine or a struct and says so itself, so one list may + each one is a number, a text, a yes/no, a colour, a texture, a state machine, an asset, an object or a struct and says so itself, so one list may hold several kinds at once. A list is compared by its items, never by identity — otherwise every reload would look like an override. - There is no **stored** list of objects: a stored list lives in the project file and an object is a - live handle that no reload survives. A list **travelling on an edge** may hold objects, though, and - `Raycast all` (#157) is what hands one out; `Item at` gives such an item back as the object it is. - The moment that list is written into a variable or a property, every object in it becomes its name - — that is the one door into a saved value, and nothing alive goes through it. A set of objects - that has to *survive* is therefore still a list of names, walked with `Repeat` and `Object by name`. - One object on its own **can** be held, by an **object variable**: write the `object` output of - `Spawn` (or of `Object by name`, `Child by name`, a collision) into it, and every later frame - reads the same object back. It lives for the run only. The file stores the declaration and an - empty value, the inspector shows `(null)` and offers nothing to pick, and neither a scene - override, a snapshot nor a save of a persistent Variables asset ever holds the object. The handle - sits beside the variable rather than in it (`core/graph/objectSlots.ts`), since everything in the - variable bag is written back into the scene as an override. A **destroyed** object reads as - `(null)`, as does one from a scene that was restarted or left. "Is it still there?" is `Equals` - with the variable on `a` and `b` left empty: true once the object is gone. Kept variables of a called behavior (#229) keep their object across calls too, - and `Properties` of type *Behavior* reads and writes another behavior's object variable. + **Objects** can be held wherever a value can (#238): an **object variable**, an **object field** of a + struct (`+ Field → Object`) and an **object item** of a list. Write the `object` output of + `Spawn` (or of `Object by name`, `Child by name`, a collision) into one, and every later frame + reads the same object back: `Expand` gives the field back as the object, `Item at` the item. + `Raycast all` (#157) hands out a list of objects, and written into a list variable it stays one. + An object lives for the run only. At rest (in the file, a snapshot, the inspector) its place + always holds the empty object, stored as `{"$object": ""}` wherever it sits, and the inspector and + the List tab show `(null)` and offer nothing to pick. During a run the object sits right in the + value, and every way out of the run empties it again (`core/graph/liveObjects.ts`, + `withoutObjects`): the values the editor run writes back into the scene as overrides, the save of + a persistent Variables asset, the live values the inspector shows and the test hooks. A struct + whose only change is an object therefore writes no override. A list that grew by an object does: + the scene learns the new item, as the empty object. A **destroyed** object reads as `(null)`, + alone as well as out of a list or a struct, as does one from a scene that was restarted or left. + "Is it still there?" is `Equals` with the object on `a` and `b` left empty: true once it is gone. + Kept variables of a called behavior (#229) keep their objects across calls too, and `Properties` + of type *Behavior* reads and writes another behavior's object variable. A list property is shown as a button saying how many items it holds; clicking it opens the **List** tab, which gives each item a row with the same widget the inspector would use for that kind — a struct item is its fields as rows under each other. The inspector stays visible beside the tab, so what the list @@ -281,7 +282,8 @@ playing use the same two words. at its declared value, and a value whose kind changed is converted like any other value. An **object variable** may sit in a persistent asset too, but is never saved: the object is an instance of that run, and the next run has new ones. It starts every run at `(null)` while the - other values go on, and the inspector says so under the switch. + other values go on, and the inspector says so under the switch. The same goes for an object in a + saved list or struct: the save keeps its place, as the empty object. - **Cross-object state** the other way: a behavior's own variables *are* the properties of its object, so another graph reads and writes them with `Object by name` → `Properties` of type *Behavior*. That reaches one named object, where a Variables asset belongs to no object at all. diff --git a/Colliders.md b/Colliders.md index 276121b..8b3aa6c 100644 --- a/Colliders.md +++ b/Colliders.md @@ -196,8 +196,9 @@ the same settings as Raycast — **Ignore owner**, **Hit triggers**, **Layers** rather than a run of the flow per hit: that is what `Count`, `Item at` and `Sub list` already work with. - `objects` and `colliders` hold **live objects**, not names — `Item at` gives one back as an object, - ready for `Destroy`, `Apply force` or `Name of`. A list only carries them while it travels: written - into a variable or a property, each object becomes its name, because nothing saved is alive. + ready for `Destroy`, `Apply force` or `Name of`. Written into a list variable they stay objects for + the rest of the run; only what leaves the run (a save, the scene) holds the empty object instead, + see [Behaviors](Behaviors). - **A collider counts once**, however many convex pieces its shape falls into, and the hit is the first face the ray enters. A **tilemap** counts once per cell the ray goes through, since a map is many solids under one entity — the `collider` of each of those hits is the tilemap. diff --git a/Development.md b/Development.md index 3673875..f1b0a86 100644 --- a/Development.md +++ b/Development.md @@ -15,7 +15,7 @@ npm run build # writes dist/ and regenerates index.html php tools/make-user.php [admin|user] # an account; every tool signs in (see Accounts) php tests/php/accounts.test.php # the API's account rules, no server needed (CI's gate job) php tests/php/snapshots.test.php # the snapshot store (#231), the same way -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1406 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1407 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