A placed tilemap grows and shrinks at every edge: the new GRID EDGES block in the inspector adds or removes one column or row at Left, Top, Right or Bottom as one undo step, shifting the cells of all layers and moving the placement through its own matrix so the content stays in place on screen; removed painted cells are kept outside the grid and return when the edge grows again, and the Columns and Rows fields of a placement keep the content in place too (#136)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0b32d3cbf3
commit
4728f4fab5
9 files changed
+588
-11
No files matched your search
@@ -40,6 +40,27 @@ async function clickInPanel(t, hook) {
|
||||
return Boolean(point);
|
||||
}
|
||||
|
||||
/**
|
||||
* The − or + button of an edge row in the inspector's GRID EDGES block (#136), scrolled into view
|
||||
* first. Both glyphs are on screen many times over, so the button is the one on the label's line.
|
||||
*/
|
||||
async function edgeButton(t, label, glyph) {
|
||||
for (let i = 0; i < 15; i++) {
|
||||
const rect = await t.json('__gm.inspectorRect()');
|
||||
const within = (p) => p.x > rect.x && p.x < rect.x + rect.w;
|
||||
const row = (await t.json(`__gm.locateAll(${JSON.stringify(label)})`)).find(within);
|
||||
if (row && row.y > rect.y + 8 && row.y < rect.y + rect.h - 8) {
|
||||
const buttons = (await t.json(`__gm.locateAll(${JSON.stringify(glyph)})`)).filter(
|
||||
(p) => within(p) && Math.abs(p.y - row.y) < 6 && p.x > row.x,
|
||||
);
|
||||
return buttons[0] ?? null;
|
||||
}
|
||||
await t.wheel(rect.x + rect.w / 2, rect.y + rect.h / 2, row && row.y < rect.y ? -200 : 200);
|
||||
await t.settle();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Whether a box lies inside another, give or take a pixel of rounding. */
|
||||
function inside(inner, outer) {
|
||||
return (
|
||||
@@ -561,6 +582,54 @@ export async function tilemap(t) {
|
||||
await undo();
|
||||
await settle();
|
||||
|
||||
// 40o. The grid grows at the left edge (#136): the cells of both layers move one column in, the
|
||||
// origin moves half a cell to the left, and on screen the painted cells stay where they were.
|
||||
const allCells = () =>
|
||||
json(
|
||||
`__gm.state.project.assets.find((a) => a.id === ${JSON.stringify(made.id)}).layers.map((l) => Object.keys(l.cells).sort().join(' '))`,
|
||||
);
|
||||
const cellsBefore = await allCells();
|
||||
const objectBefore = await t.object(MAP_OBJECT);
|
||||
const screenBefore = await json(`__gm.tilemap.cellAt(${JSON.stringify(MAP_OBJECT)}, 1, 1)`);
|
||||
const addLeft = await edgeButton(t, 'Left', '+');
|
||||
if (addLeft) await click(addLeft.x, addLeft.y);
|
||||
await settle();
|
||||
await shot('40-grid-edges');
|
||||
const cellsGrown = await allCells();
|
||||
const objectGrown = await t.object(MAP_OBJECT);
|
||||
const screenGrown = await json(`__gm.tilemap.cellAt(${JSON.stringify(MAP_OBJECT)}, 2, 1)`);
|
||||
const drawnGrown = await json(`__gm.tilemap.info(${JSON.stringify(MAP_OBJECT)})`);
|
||||
const movedIn = (keys) =>
|
||||
keys
|
||||
.split(' ')
|
||||
.filter(Boolean)
|
||||
.map((key) => key.split(',').map(Number))
|
||||
.map(([x, y]) => `${x + 1},${y}`)
|
||||
.sort()
|
||||
.join(' ');
|
||||
check(
|
||||
'the + of the left edge moves every layer one column in and the map stays where it is on screen',
|
||||
addLeft !== null &&
|
||||
cellsGrown.length === 2 &&
|
||||
cellsGrown.every((keys, i) => keys === movedIn(cellsBefore[i])) &&
|
||||
objectGrown.overrides.columns === COLUMNS + 1 &&
|
||||
Math.abs(objectGrown.position.x - (objectBefore.position.x - 24)) < 1e-6 &&
|
||||
Math.abs(screenGrown.x - screenBefore.x) < 0.5 &&
|
||||
Math.abs(screenGrown.y - screenBefore.y) < 0.5 &&
|
||||
drawnGrown.tiles === 10,
|
||||
JSON.stringify({ addLeft, cellsBefore, cellsGrown, objectGrown, screenBefore, screenGrown, drawnGrown }),
|
||||
);
|
||||
await undo();
|
||||
await settle();
|
||||
const objectUndone = await t.object(MAP_OBJECT);
|
||||
check(
|
||||
'and one undo takes back the cells, the column and the position',
|
||||
JSON.stringify(await allCells()) === JSON.stringify(cellsBefore) &&
|
||||
objectUndone.overrides.columns === undefined &&
|
||||
JSON.stringify(objectUndone.position) === JSON.stringify(objectBefore.position),
|
||||
JSON.stringify({ cells: await allCells(), objectUndone }),
|
||||
);
|
||||
|
||||
// 40j. The running game draws the same map: it is scene content, not editor decoration. The map
|
||||
// is moved in front of the camera for this, because an object off screen is culled there.
|
||||
await mutate(`
|
||||
|
||||
Reference in new issue
Block a user