Each tilemap layer has its own Z: an offset added to the Z of the placed tilemap, like a child's Z to its parent, default 0 keeps the previous order (layers right after their map, in list order), a negative Z sorts a layer below the map, on a tie layers keep their list order and follow the hierarchy against other objects; editor scene and game use the same order through the new pure function drawSlots, a tilemap draws into one container per layer, and the tilemap panel gains a Z field for the selected layer with one undo step per change (#174)
game-maker / gate (push) Successful in 1m58s
game-maker / suite (push) Successful in 6m50s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-19 14:03:20 +02:00
1 parent 5385d9e152
commit 47eea2f6e4
13 files changed
+389 -38

No files matched your search

+28
View File
@@ -245,6 +245,34 @@ export class RenameTilemapLayerCommand implements Command {
}
}
/** A layer's `z` above its tilemap's (#174); 0 is stored as nothing, the way a layer starts out. */
export class SetTilemapLayerZCommand implements Command {
readonly label = 'Set layer z';
private previous: number | undefined;
constructor(
private readonly assetId: string,
private readonly layerId: string,
private readonly z: number,
) {}
execute(project: Project): void {
if (!Number.isFinite(this.z)) throw new CommandError('A layer z is a number');
const layer = requireTilemapLayer(project, this.assetId, this.layerId);
this.previous = layer.z;
setLayerZ(layer, this.z);
}
undo(project: Project): void {
setLayerZ(requireTilemapLayer(project, this.assetId, this.layerId), this.previous ?? 0);
}
}
function setLayerZ(layer: TilemapLayer, z: number): void {
if (z === 0) delete layer.z;
else layer.z = z;
}
/** A hidden layer keeps its cells and is left out of the drawing, in the editor and in the game alike. */
export class SetTilemapLayerHiddenCommand implements Command {
readonly label: string;
+4 -1
View File
@@ -213,12 +213,15 @@ export interface TileAsset extends AssetBase {
/**
* One drawing layer of a tilemap: `cells` maps `"x,y"` to the id of the tile lying there, and a
* layer nobody switched off is drawn. Which of that tile's quarters a cell shows is worked out
* from its neighbours while drawing, never stored – see `model/tilemap.ts`.
* from its neighbours while drawing, never stored – see `model/tilemap.ts`. `z` is added to the `z`
* of the placed tilemap (#174), as a child's is to its parent's, so every placement of the map
* keeps its layers apart by the same steps; layers of equal `z` keep their list order.
*/
export interface TilemapLayer {
id: string;
name: string;
hidden?: boolean;
z?: number;
cells: Record<string, string>;
}
+5
View File
@@ -72,6 +72,11 @@ export function isLayerVisible(layer: TilemapLayer): boolean {
return layer.hidden !== true;
}
/** How far a layer is drawn above its tilemap's own `z` (#174); a layer never given one sits on it. */
export function layerZ(layer: TilemapLayer): number {
return layer.z ?? 0;
}
export function findLayer(asset: { layers: TilemapLayer[] }, layerId: string): TilemapLayer | undefined {
return asset.layers.find((layer) => layer.id === layerId);
}
+1
View File
@@ -546,6 +546,7 @@ function normalizeLayers(raw: unknown): TilemapLayer[] {
if (parseCellKey(key) && typeof value === 'string' && value !== '') cells[key] = value;
const layer: TilemapLayer = { id: l.id, name: typeof l.name === 'string' ? l.name : 'Layer', cells };
if (l.hidden === true) layer.hidden = true;
if (typeof l.z === 'number' && Number.isFinite(l.z) && l.z !== 0) layer.z = l.z;
layers.push(layer);
}
return layers;