Add the Structs page for struct assets (#253)
New page Structs with sidebar entry. Behaviors, Architecture and Development point to it. Check total 1500.
1 parent
40027db357
commit
2a1ce85981
5 files changed
+98
-5
No files matched your search
+2
-2
@@ -73,9 +73,9 @@
|
||||
|
||||
```
|
||||
web/index.html Vite source page (dev) index.html built page (generated, served)
|
||||
src/core/model/ Project (object holders), Asset + AssetTypes, SceneObject, Properties (value types), hierarchy, walk (generic parent/child walks), instance (container content resolved from its template), usages (where an asset is used), container (the cycle guard), placement (what may be dropped where), texture (frames, the slice grid, a frame's collision outlines), frameOutline (#193: a frame's outlines as a collider wears them, centred, a pixel to a unit, cut into pieces once per drawn list), traceCollision (#161: a frame's outlines read off its picture — the pixels from an alpha threshold on are solid, each 4-connected island is walked round along the pixel edges and cut down to a few corners without ever crossing itself; crumbs below 1 % of the frame drop out), generated (pictures that are drawn rather than uploaded, #185: the key `gen:<assetId>@<revision>`, the register of readers that tell the picture path an asset's canvas size and revision, and the `fingerprint` pixel art and vector art make their revision with), vectorart (#129: the canvas as a property, which ring is worth drawing, and the revision as a fingerprint of the drawing rather than a counter, a texture fill's picture included) + vectorPath (what a shape draws, as plain commands: closed rings fill, every ring strokes, a segment is a line while neither of its ends carries a handle; a paint resolved to sorted stops or the picture it names) + vectorPaint (#186: gradients and texture fills — where a paint lies when it is switched on, the colour between two stops, adding, moving and removing a stop, a paint moved with its shape, and the rule that a texture fill takes uploaded pictures only) + vectorBoolean (#187: union, subtract, intersect and exclude on the sampled outlines, each shape read by the even-odd rule; the result rings in the order Pixi's hole detection needs, every outline followed by its holes and preceded by the islands inside them) + vectorCurves (#208: every sampled point remembers its cubic and its `t`, so a run of result points along one cubic becomes that cubic again, cut with de Casteljau), pixelart (#130: the palette a picture is painted in, how the layers of a frame come together, the sheet of all frames, a frame id read as a cut of it, and the revision) + pixelCel (the file of one layer on one frame, and its SHA-256 name worked out in the browser) + pixelDraw (what the tools do to the indices: brush, line, rectangle, ellipse, fill, resize about an anchor, merge, a palette colour taken out) + pixelEdit (every edit of layers, frames and cels as a function from one state to the next), polygon (an outline checked, cut into convex pieces and clipped to a rectangle), tile (the three kinds and their block shapes, reading a tile's pictures, the animation step), autotile (which quarter tile a neighbourhood asks for, the 47/16 tiles a block produces, 1 for a plain tile), tilemap (the cells of a layer, which neighbours a cell is joined to, the cells a stroke or a rectangle covers), tilemapCollision (the solid cells of a map, drawn in or out by their tile's collision scale and merged into rectangles, one group per one-way angle and per surface (`tileMaterials`, #193), the outlined cells as polygons — an autotile's outlines cut into its quarters and pieced together per cell like its picture —, where one sits in the world, and which cells of a placed map a world rectangle can reach, in cells (`cellsWithin`, #184)), tilemapMemo (what a map's cells work out to, kept while they hold the same: a version per cell map compared cell by cell, since strokes paint in place), animation (which frame at time t, a row's value there, what a row may aim at, the players on an object; KeyRef and its lookups) + animationPreview (the root at a frame, written into copies), curve (#247: a drawn easing evaluated at t — each segment a cubic solved for t by bisection, held to its rules by `sanitizedCurve`: ends at 0 and 1, no point overtaking another, no handle past its neighbour — and which keys and `Lerp` nodes use one) + curvePresets (the built-in eases traced as curves, a segment halved only where it strays), graphLookup (what a graph sees of the project: behaviors to run, state machines to read, curves to ease along), Scope (how long a shared value lives: per instance, one for the run, or one per scene and rebuilt with every scene that loads, #164 — for a state machine's current state and for the values of a Variables asset), collisionLayers (which colliders may meet: the project's named layers, a collider's layer and mask, and the one rule `layersMeet` the engine, Solids and the event pair search all answer by)
|
||||
src/core/model/ Project (object holders), Asset + AssetTypes, SceneObject, Properties (value types), hierarchy, walk (generic parent/child walks), instance (container content resolved from its template), usages (where an asset is used), container (the cycle guard), placement (what may be dropped where), texture (frames, the slice grid, a frame's collision outlines), frameOutline (#193: a frame's outlines as a collider wears them, centred, a pixel to a unit, cut into pieces once per drawn list), traceCollision (#161: a frame's outlines read off its picture — the pixels from an alpha threshold on are solid, each 4-connected island is walked round along the pixel edges and cut down to a few corners without ever crossing itself; crumbs below 1 % of the frame drop out), generated (pictures that are drawn rather than uploaded, #185: the key `gen:<assetId>@<revision>`, the register of readers that tell the picture path an asset's canvas size and revision, and the `fingerprint` pixel art and vector art make their revision with), vectorart (#129: the canvas as a property, which ring is worth drawing, and the revision as a fingerprint of the drawing rather than a counter, a texture fill's picture included) + vectorPath (what a shape draws, as plain commands: closed rings fill, every ring strokes, a segment is a line while neither of its ends carries a handle; a paint resolved to sorted stops or the picture it names) + vectorPaint (#186: gradients and texture fills — where a paint lies when it is switched on, the colour between two stops, adding, moving and removing a stop, a paint moved with its shape, and the rule that a texture fill takes uploaded pictures only) + vectorBoolean (#187: union, subtract, intersect and exclude on the sampled outlines, each shape read by the even-odd rule; the result rings in the order Pixi's hole detection needs, every outline followed by its holes and preceded by the islands inside them) + vectorCurves (#208: every sampled point remembers its cubic and its `t`, so a run of result points along one cubic becomes that cubic again, cut with de Casteljau), pixelart (#130: the palette a picture is painted in, how the layers of a frame come together, the sheet of all frames, a frame id read as a cut of it, and the revision) + pixelCel (the file of one layer on one frame, and its SHA-256 name worked out in the browser) + pixelDraw (what the tools do to the indices: brush, line, rectangle, ellipse, fill, resize about an anchor, merge, a palette colour taken out) + pixelEdit (every edit of layers, frames and cels as a function from one state to the next), polygon (an outline checked, cut into convex pieces and clipped to a rectangle), tile (the three kinds and their block shapes, reading a tile's pictures, the animation step), autotile (which quarter tile a neighbourhood asks for, the 47/16 tiles a block produces, 1 for a plain tile), tilemap (the cells of a layer, which neighbours a cell is joined to, the cells a stroke or a rectangle covers), tilemapCollision (the solid cells of a map, drawn in or out by their tile's collision scale and merged into rectangles, one group per one-way angle and per surface (`tileMaterials`, #193), the outlined cells as polygons — an autotile's outlines cut into its quarters and pieced together per cell like its picture —, where one sits in the world, and which cells of a placed map a world rectangle can reach, in cells (`cellsWithin`, #184)), tilemapMemo (what a map's cells work out to, kept while they hold the same: a version per cell map compared cell by cell, since strokes paint in place), animation (which frame at time t, a row's value there, what a row may aim at, the players on an object; KeyRef and its lookups) + animationPreview (the root at a frame, written into copies), curve (#247: a drawn easing evaluated at t — each segment a cubic solved for t by bisection, held to its rules by `sanitizedCurve`: ends at 0 and 1, no point overtaking another, no handle past its neighbour — and which keys and `Lerp` nodes use one) + curvePresets (the built-in eases traced as curves, a segment halved only where it strays), graphLookup (what a graph sees of the project: behaviors to run, state machines to read, curves to ease along), structTypes (#253: Struct assets as types — every typed struct variable, struct field and `Pack`/`Expand` found and brought in line with its asset, a renamed field carried through every value first, the cycle rule), Scope (how long a shared value lives: per instance, one for the run, or one per scene and rebuilt with every scene that loads, #164 — for a state machine's current state and for the values of a Variables asset), collisionLayers (which colliders may meet: the project's named layers, a collider's layer and mask, and the one rule `layersMeet` the engine, Solids and the event pair search all answer by)
|
||||
src/core/properties/ PropertySchema, kinds (one row per value kind), listItems (an item's kind, read off its value), resolve (the only override merge), deviation (what is gold), collider/camera/bounds geometry (with the side a one-way collider blocks from, and the rectangle around a shape a broad phase looks at first, #184), convex (capsules and polygons: rounded convex pieces against each other), ray (where a ray meets a shape, in double precision), rigidbody (what the engine reads off a rigidbody, a collider's material and the scene), aspect, enabled, editorRun, assetRef/textureRef (how a reference reads), declaredRows (the row a Property node declares in a shader or particle graph, and the params that node has in both)
|
||||
src/core/util/ list (take out, put back and move an item — what a command's undo is made of), vec (dot, the closest point on a segment — shared by the collider maths, the outline hit area and the polygon grips), color (`mixColor`, channel by channel — keys of an animation, stops of a gradient, the particles' Mix colour)
|
||||
src/core/util/ list (take out, put back and move an item — what a command's undo is made of), vec (dot, the closest point on a segment — shared by the collider maths, the outline hit area and the polygon grips), color (`mixColor`, channel by channel — keys of an animation, stops of a gradient, the particles' Mix colour), recorder (#253: assignments taken back last first — the undo of an edit whose reach is not known in advance)
|
||||
src/core/commands/ undoable commands (pixelArtCommands: one command runs any pixel art edit and keeps the state before it, #130), CommandStack, SetBagValueCommand base, RenameCommand base (undone by renaming back: variable, struct field, port), MoveCommand base (undone by moving back: tile picture, tilemap layer, vector shape), vectorArtCommands (#129: the shapes of a drawing, one gesture one command), one import command shape for texture/font/sound, require.ts (validated lookups, and what an instance may not change), naming.ts
|
||||
src/core/graph/ graph model, NodeRegistry/NodeContext/values (a travelling list may hold live objects, `storedList`
|
||||
narrows one down to what a PropertyBag may hold, #157), interpreter, dropTarget, nested (behaviors as nodes),
|
||||
|
||||
+3
-2
@@ -230,8 +230,9 @@ playing use the same two words.
|
||||
dropped on load, in a node setting or on the way through a graph. There is no depth limit either.
|
||||
A struct inside a struct field is **declared** (`fields` on the field, like a struct variable),
|
||||
while a list still declares nothing about its items, so a struct item in a list takes its shape
|
||||
from its value at any depth. Named struct types that several variables share are a topic of their
|
||||
own. `Pack`, `Expand` and `Item at` take nested data apart **one level at a time**: a struct in a
|
||||
from its value at any depth. A struct may also follow a **struct asset** instead of declaring its
|
||||
fields itself (#253): its Type row picks one, and `Pack`/`Expand` have a Type setting that makes
|
||||
their ports the asset's fields — see [Structs](Structs). `Pack`, `Expand` and `Item at` take nested data apart **one level at a time**: a struct in a
|
||||
struct is two `Expand` nodes in a row, and there is no path syntax like `a.b[2].c`. `+ Item`
|
||||
offers every kind, on a list of its own and on one a struct field holds alike. A live entity is
|
||||
an object on a data edge too, so it carries a `Symbol` brand (`ENTITY_HANDLE`) that no struct
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ npm run build # writes dist/ and regenerates index.html
|
||||
php tools/make-user.php <name> <password> [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 # 1486 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1500 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
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
A **struct asset** is a named shape for structs. Instead of typing the same fields into every
|
||||
struct variable that holds, say, a piece of loot, you declare `Loot` once — `Title`, `Amount`,
|
||||
`Rare` with their defaults — and let the variables, struct fields and `Pack`/`Expand` nodes that
|
||||
hold loot **follow** it. Change `Loot`, and all of them change with it.
|
||||
|
||||
A struct that declares its own fields, as every struct did before, still works exactly as it did.
|
||||
A type is something you give a struct, not something it needs.
|
||||
|
||||
## Making one
|
||||
|
||||
**+ → Struct** creates the asset; it stands in the assets panel under *Structs*. Its inspector has
|
||||
a **FIELDS** section that works like the VARIABLES section of a behavior or a Variables asset:
|
||||
|
||||
- **+ Field** adds a field of any kind — a number, a text, a yes/no, a colour, a texture, an asset,
|
||||
an object, a list or a struct.
|
||||
- The name field renames it, the remove button at the end of the row removes it.
|
||||
- The value next to it is the field's **default**: what a struct of this type starts with.
|
||||
- **Open** shows the fields in a tab of their own, as it does for variables.
|
||||
|
||||
A field may itself be a struct with a type. What it may not be is its own type, directly or through
|
||||
another type: `Loot` cannot hold a `Loot`, and if `Chest` holds a `Loot`, `Loot` cannot hold a
|
||||
`Chest`. Such a value would never end. The type picker does not offer those types. A **list** field
|
||||
is fine — it starts empty.
|
||||
|
||||
## Giving a struct a type
|
||||
|
||||
Every struct variable, and every struct field inside one, has a **Type** row under its head. It
|
||||
reads **Own fields** while the struct declares its fields itself. Its menu offers:
|
||||
|
||||
- **Own fields** — the struct keeps the fields it has now and declares them itself again.
|
||||
- **every struct asset** — the struct takes on that asset's fields. What its value already holds
|
||||
under the same name stays, if it fits the field's kind. Every other field starts at the default
|
||||
the asset declares. A field the asset does not have goes.
|
||||
- **Make struct type** — turns the fields the struct holds by itself into a new struct asset,
|
||||
named after the variable. The value it holds now becomes the asset's defaults, so nothing reads
|
||||
differently afterwards. This is the way to turn an existing struct into a type.
|
||||
|
||||
With a type, the fields are no longer edited at the variable: there is no **+ Field**, and the
|
||||
field names cannot be changed or removed there. The **values** stay per variable, and a placed
|
||||
object may still override them, as with any variable.
|
||||
|
||||
## Pack and Expand
|
||||
|
||||
`Pack` and `Expand` have a **Type** setting. With a type, their ports are the asset's fields — one
|
||||
input per field on `Pack`, one output per field on `Expand` — and they follow the asset from then
|
||||
on. The FIELDS section of such a node lists them without letting you change them. Without a type,
|
||||
the fields are declared on the node by hand as before (**+ Field**, **From variable**).
|
||||
|
||||
## When the asset changes
|
||||
|
||||
Every change to a struct asset's fields reaches every place of that type at once, and **one undo**
|
||||
takes all of it back:
|
||||
|
||||
| Change on the asset | What happens at each place |
|
||||
|---|---|
|
||||
| Field added | Every value gets it, at the field's default. `Pack`/`Expand` get a port. |
|
||||
| Field removed | It leaves every value. The port goes, and with it the edge on it and the value typed into it. |
|
||||
| Field renamed | Every value keeps its value under the new name, overrides included. The port is renamed and keeps its edge. |
|
||||
| Default changed | Nothing: a default is what a *new* struct of the type starts with. |
|
||||
|
||||
This also works through several levels: if `Chest` holds a `Loot` and a variable holds a `Chest`, a
|
||||
field renamed on `Loot` is renamed inside that variable's value too.
|
||||
|
||||
## Deleting a struct asset
|
||||
|
||||
The delete dialog counts the structs and `Pack`/`Expand` nodes that use it. After deleting, each of
|
||||
them **keeps the fields it last had**, now as its own fields — no value is lost, only the link. Its
|
||||
Type row reads **Own fields** again.
|
||||
|
||||
## In the running game
|
||||
|
||||
Nothing changes there. A struct value is the same plain bundle of fields, with or without a type:
|
||||
the type does not travel with the value, so `Equals`, `Index of`, saving and loading treat it as
|
||||
before. Edges do not check the type either — any struct fits any struct port.
|
||||
|
||||
## What it does not do (yet)
|
||||
|
||||
Lists stay **untyped**: a list of structs still takes each item's shape from the item itself, and
|
||||
**+ Item → Struct** starts an empty struct. Typed lists, where every item is one struct type, are
|
||||
[issue #254](https://git.nockal.com/meleki/game-maker/issues/254).
|
||||
|
||||
## Under the hood
|
||||
|
||||
A typed struct keeps a **copy** of the type's fields in its declaration (`fields`), next to
|
||||
`structType`, the asset's id. Everything that reads a struct's fields therefore works unchanged.
|
||||
`syncStructTypes` in `src/core/model/structTypes.ts` brings every copy, every value kept for it and
|
||||
every typed `Pack`/`Expand` back in line; it runs after each change to a struct asset and when a
|
||||
project is loaded, so a hand-edited file heals too. Its writes go through a `Recorder`
|
||||
(`src/core/util/recorder.ts`), which is what makes an edit of unknown reach one undo step. A struct
|
||||
asset declares its fields as `variables`, so the variable commands and the inspector's variable
|
||||
rows edit them unchanged.
|
||||
+1
@@ -5,6 +5,7 @@
|
||||
- [Scenes](Scenes)
|
||||
- [Scene editing](Scene-editing)
|
||||
- [Behaviors](Behaviors)
|
||||
- [Structs](Structs)
|
||||
- [Colliders](Colliders)
|
||||
- [Physics](Physics)
|
||||
- [Textures](Textures)
|
||||
|
||||
Reference in new issue
Block a user