Let a tilemap layer sort its rows by Y with the objects (#228)
A tilemap layer was one piece in the draw order, so a figure stood either in front of a whole layer of trees or behind all of it. For a top-down game the trees in front of the figure's feet have to cover it and the ones behind must not. - A new "Sort by Y" box under the layer list sets `sortByY` on the painted layer. Every change is its own undo step. - Such a layer comes as one draw slot per row. On its `z`, the rows and all objects on that `z` are sorted by where they stand: the bottom of an object's box, the bottom of a row. Ties keep the hierarchy order, and other `z` values are untouched. - A layer drawn as one piece and the map's own node stay behind the sorted ones on the same `z`, since neither has a single place to stand. Ground belongs on a lower `z` or stays unsorted. - A new tile property "Sort offset" (whole rows, -16 to 16) lets a crown sort with the trunk below it. - `TilemapField` draws a container per row for such a layer, and picking takes the row into account, so a click picks what is drawn in front. Scene view, game view and play share the same rule. Limits: on a rotated map "down" is world Y. A layer sorted by Y costs about one draw call per row and tile instead of one per tile. Tests: - ./check.sh: 160 files, 2350 tests, CHECK EXIT 0 (before 2340). - 10 new unit tests in tests/viewport/sort-by-y.test.ts. - e2e 39-43: ALL PASSED, 148 checks. New check 40p-iii ticks the box and finds the slot of row 0, undo brings back the whole layer. - Counter checks: without the Y sort 5 unit tests fail, with the offset ignored 5, with no row in picking 1. If TilemapField draws no rows, exactly 40p-iii fails in e2e. - The e2e sum in the README is 1378, counted, not yet seen in CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ffb5bbe039
commit
50854389bb
16 files changed
+467
-51
No files matched your search
@@ -571,6 +571,29 @@ export async function tilemap(t) {
|
||||
JSON.stringify({ withZ, orderZ, orderBack, zBack }),
|
||||
);
|
||||
|
||||
// 40p-iii. Sort by Y (#228) draws the painted layer row by row: its one cell (4,0) becomes the
|
||||
// slot of row 0 in place of the whole layer's. Undone again for the blocks below.
|
||||
const sortBox = await inPanel(t, '__gm.tilemap.sortByYAt()');
|
||||
if (sortBox) await click(sortBox.x, sortBox.y);
|
||||
await settle();
|
||||
const sortedLayer = (await json(`__gm.tilemap.layers(${JSON.stringify(made.id)})`))[1];
|
||||
const orderSorted = await json('__gm.drawOrder()');
|
||||
const boxSorted = await json('__gm.tilemap.sortByYAt()');
|
||||
await undo();
|
||||
await settle();
|
||||
const orderUnsorted = await json('__gm.drawOrder()');
|
||||
check(
|
||||
'Sort by Y draws the painted layer as one slot per row, and undo makes it one piece again',
|
||||
sortBox?.checked === false &&
|
||||
sortedLayer.sortByY === true &&
|
||||
boxSorted?.checked === true &&
|
||||
orderSorted.includes(`${upperSlot}#0`) &&
|
||||
!orderSorted.includes(upperSlot) &&
|
||||
orderUnsorted.includes(upperSlot) &&
|
||||
!orderUnsorted.includes(`${upperSlot}#0`),
|
||||
JSON.stringify({ sortBox, sortedLayer, boxSorted, orderSorted, orderUnsorted }),
|
||||
);
|
||||
|
||||
// 40p-ii. The duplicate mark copies the painted layer right above it, cells and all, and paints
|
||||
// on the copy. Undone again: the blocks below count on two layers.
|
||||
const copyMark = await inPanel(t, '__gm.tilemap.duplicateLayerAt()');
|
||||
|
||||
Reference in new issue
Block a user