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)
game-maker / gate (push) Successful in 1m43s
game-maker / suite (push) Successful in 6m8s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-18 13:58:03 +02:00
1 parent 0b32d3cbf3
commit 4728f4fab5
9 files changed
+588 -11

No files matched your search

+50
View File
@@ -17,6 +17,8 @@ import { findAssetOf, type Project } from './Project';
export const TILEMAP_COLUMNS_KEY = 'columns';
export const TILEMAP_ROWS_KEY = 'rows';
export const TILEMAP_TILE_KEY = 'tileSize';
/** The most columns or rows a grid may have – the schema's limit, and the edge buttons' too. */
export const TILEMAP_MAX_CELLS = 1000;
/**
* The grid is read from a property bag rather than from the asset: a placed tilemap may override
@@ -163,6 +165,54 @@ export function cellOrigin(props: PropertyBag, x: number, y: number): { x: numbe
return { x: x * tile - w / 2, y: y * tile - h / 2 };
}
/** A side of the grid that grows or shrinks (#136). */
export type TilemapEdge = 'left' | 'top' | 'right' | 'bottom';
export const TILEMAP_EDGES: readonly TilemapEdge[] = ['left', 'top', 'right', 'bottom'];
/** Left and right change the columns, top and bottom the rows. */
export function edgeSizeKey(edge: TilemapEdge): string {
return edge === 'left' || edge === 'right' ? TILEMAP_COLUMNS_KEY : TILEMAP_ROWS_KEY;
}
/**
* One layer's cells moved by whole cells. Growing at the left or top edge is this: cell `0,0` is
* always the top-left corner, so what was painted moves one column or row further in. Nothing is
* dropped – a cell pushed below zero lies outside the grid and comes back when the edge grows again.
*/
export function shiftedCells(cells: Record<string, string>, dx: number, dy: number): Record<string, string> {
const moved: Record<string, string> = {};
for (const [key, tileId] of Object.entries(cells)) {
const at = parseCellKey(key);
if (at) moved[cellKey(at.x + dx, at.y + dy)] = tileId;
}
return moved;
}
/**
* How far the origin moves, in the tilemap's own frame, for the painted cells to stay where they are
* when `edge` gains `count` cells (negative removes them). The grid is centred on the origin, so
* every added column pushes the content half a cell away from that edge; the origin follows by as
* much the other way.
*/
export function edgeCompensation(
edge: TilemapEdge,
count: number,
tileSize: number,
): { x: number; y: number } {
const half = (count * tileSize) / 2;
switch (edge) {
case 'left':
return { x: -half, y: 0 };
case 'right':
return { x: half, y: 0 };
case 'top':
return { x: 0, y: -half };
case 'bottom':
return { x: 0, y: half };
}
}
/** The cells of the rectangle between two corners, both included and clipped to the grid. */
export function cellsInRect(
props: PropertyBag,