Describe sorting by Y, the tile sort offset and the frame sort line (#228)

admin committed 2026-09-24 19:34:44 +02:00
1 parent 8b8da5008d
commit daeeaf9fe8
6 files changed
+55 -3

No files matched your search

+1 -1
@@ -131,7 +131,7 @@ src/viewport/ view (transforms), items (what to draw), symbols (how to
CPU and laid side by side onto one canvas, so a frame is cut out like a texture frame),
SoundLibrary, ShaderLibrary, ParticleLibrary,
particles (one ParticleContainer per source), tilemap (one container per layer),
drawOrder (objects and tilemap layers by z, #174), activeCamera — no editor concepts,
drawOrder (objects and tilemap layers by z, #174, rows of a layer sorted by Y, #228), activeCamera — no editor concepts,
so tests reach it freely
src/editor/ App → Editor (layout + ticker), PlaySession (the run),
ProjectSession (load/create/delete plus the top bar's one menu, #183),
+1 -1
@@ -14,7 +14,7 @@ npm run build # writes dist/ and regenerates index.html
./build.sh # the same under `set -o pipefail`, for callers that pipe the output
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)
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1377 editor checks, screenshots in /tmp/gm-e2e-*.png
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1380 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
+2
@@ -56,6 +56,8 @@ icon. Beside the icons the sprite underneath is picked as before.
`z` is drawn on top; objects with equal `z` keep their hierarchy (tree) order. It is edited in the
inspector next to X/Y, undoable like any move, and applies in edit and play mode alike. The layers
of a tilemap are sorted in one by one, each at the map's `z` plus its own (see [Tilemaps](Tilemaps), #174).
On the `z` of a layer sorted by Y, Y decides instead: whatever stands higher up is drawn first
(see [Tilemaps](Tilemaps#sorting-by-y), #228).
**Transform.** Sprites, texts, colliders and containers carry four more rows next to their
position: **Scale** (one factor, default 1), **Rotation** (degrees, positive turns clockwise on
+17
@@ -163,6 +163,23 @@ drawn twice as big beside a pattern at its old size reads as two different pictu
sprite narrower than its borders applies to the scaled size: two 32-unit borders on a 20-unit box
become two of 10.
## Sort line — where a figure stands
On a tilemap layer sorted by Y (see [Tilemaps](Tilemaps#sorting-by-y)) a sprite is sorted by the
bottom edge of its box. A figure with a shadow or a few empty pixels below its feet would then stand
too low. A frame's **Sort line** moves that point up: whole image pixels from the frame's bottom
edge, 0 by default, at most the frame's height. A sprite wearing the frame stands that share of its
box higher up, so a line 6 px up a 24 px frame lifts a 48-unit sprite by 12 units.
- It lives on **the frame**, not on the texture, because one texture can hold several sheets with
figures of different sizes. The frames of one walk cycle want the same value, or the figure
changes its place in the order while it walks.
- In the **Texture tab** the selected frame shows it as a dashed yellow line with a knob left of the
frame. At 0 the line lies on the bottom edge together with the bottom border and a resize handle,
so grab it by the knob; a line inside the frame can also be dragged directly. The inspector has
the same number under *Sorting*. One drag or one typed value is one undo step.
- 0 carries no key in the saved document. It only matters on a Z with a layer sorted by Y.
**Fitting the sprite to the picture.** The *Width* and *Height* rows of a sprite carry a ↔ / ↕
button offering two things: **Fit to 64 x 48** sets that one side from the other and the picture's
proportions — the frame's rectangle when it wears a frame, the whole image otherwise — and **Set
+30
@@ -128,6 +128,8 @@ The layer's settings (#138):
Z keep their list order; against other objects of equal Z the hierarchy decides, as always.
One undo step per change; the running game draws the same order, and a map whose Z a run changes
takes its layers with it.
- **Sort by Y** (#228), the box under the list, sorts the chosen layer row by row with every object
on its Z, see [Sorting by Y](#sorting-by-y). Off by default, one undo step per change.
- **Show** decides how the scene view draws the *other* layers of the selected map: **All layers**
as they are, **Others faded** at 30 %, or **Active layer only**. It is a way of looking while you
paint, not a property of the map: it touches neither the project nor the game, a map that is not
@@ -137,6 +139,34 @@ The **+** in the header of the list appends a layer on top. The **✕** at the r
removes that layer, cells and all. A tilemap always keeps at least one layer — there has to be
something to paint on, so the last one has no ✕.
### Sorting by Y
For top-down maps a layer can be **sorted by Y** (#228): trees, fences and houses a figure walks
both behind and in front of. With the box ticked the layer is no longer one piece in the drawing
order but **one slot per row**, and everything on that layer's Z is sorted by where it stands:
- a **row** of the layer by the bottom edge of its cells,
- an **object** by the bottom edge of its box, which for a figure is its feet. A sprite whose frame
has a **Sort line** (see [Textures](Textures)) stands on that line
instead, for a figure drawn with a shadow or empty pixels below its feet.
Whatever stands higher up on screen is drawn first. A figure below a trunk's row is drawn in front
of the tree, a figure above it behind. Objects on that Z sort among each other the same way. Ties
keep the usual order: the hierarchy, and between layers their list order.
- Only the Z of a sorted layer is affected. Objects and layers on every other Z are drawn as
before, so switching the box on changes nothing elsewhere in the scene.
- On that Z a layer that is **not** sorted, and the map itself, stay behind everything sorted:
neither has one place to stand. Keep the ground on a Z of its own below, or on the same Z unsorted.
- A tree whose **crown** is a row above its trunk would sort by its own row, so a figure right under
the crown would stand in front of it. Give the crown tile a **Sort offset** of 1 (see
[Tiles](Tiles)): its cells then sort with the row below, the trunk's. A crown two rows tall gets
2 on its upper tile.
- Each row is drawn with one mesh per tile, so a sorted layer costs about one draw call per row and
tile instead of one per tile.
- The scene view, the game view and the running game sort the same way, and a click picks what is
drawn in front.
## In the running game
A tilemap is scene content, not editor decoration: it is drawn in the game exactly as in the
+4 -1
@@ -99,11 +99,14 @@ asks for; a picture that does not fit is kept and named, never silently dropped.
- **Collision scale** — 1 by default. How big a solid cell blocks against its square, drawn in or
out only on the sides without a blocking neighbour (#140); see
[Tilemaps](Tilemaps#collision-scale).
- **Sort offset** — 0 by default, a whole number of rows from -16 to 16. On a layer sorted by Y a
cell of this tile is sorted as if it stood that many rows further down (#228): a treetop at 1
sorts with the trunk below it. See [Tilemaps](Tilemaps#sorting-by-y).
- A tile whose picture is a frame with **collision outlines** blocks with them instead of its
square (#141) – an autotile with its outlines cut into the same quarters as its picture; see
[Tilemaps](Tilemaps#outlined-tiles).
Kind, rate, playback, the solid switch and the collision scale are ordinary properties, so the inspector shows them like any other asset's
Kind, rate, playback, the solid switch, the collision scale and the sort offset are ordinary properties, so the inspector shows them like any other asset's
— undo, defaults and the gold mark for a non-default value come for free.
## The tab