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

+21 -3
View File
@@ -13,19 +13,21 @@ import {
RemoveTilemapLayerCommand,
RenameTilemapLayerCommand,
SetTilemapLayerHiddenCommand,
SetTilemapLayerZCommand,
} from '../../core/commands/tilemapCommands';
import type { Command } from '../../core/commands/Command';
import type { TilemapAsset } from '../../core/model/Asset';
import { findObject } from '../../core/model/hierarchy';
import { resolvedHolder } from '../../core/model/instance';
import { findAssetOf } from '../../core/model/Project';
import { findLayer, isLayerVisible } from '../../core/model/tilemap';
import { findLayer, isLayerVisible, layerZ } from '../../core/model/tilemap';
import {
Button,
Checkbox,
Dropdown,
HStack,
Menu,
NumberField,
Panel,
ScrollContainer,
TextField,
@@ -134,6 +136,8 @@ export interface TilemapPanelWidgets {
layers: { id: string; name: Button; visible: Checkbox; up: Button; down: Button; remove: Button }[];
/** The name of the layer painted on (#138). */
layerName: TextField;
/** Its `z` above the map's own (#174). */
layerZ: NumberField;
/** How the other layers are shown in the scene view (#138). */
focus: Dropdown;
addLayer: Button;
@@ -236,7 +240,8 @@ function buildPanelContent(host: InspectorHost, asset: TilemapAsset): void {
const { state } = host;
const paint = state.tilemapPaint;
const painted = paintedLayerId(state, asset);
const paintedName = findLayer(asset, painted)?.name ?? '';
const paintedLayer = findLayer(asset, painted);
const paintedName = paintedLayer?.name ?? '';
const layerName: TextField = new TextField(paintedName, {
onChange: (name) => {
// The command rejects a blank name but cannot put the old text back into the field,
@@ -245,6 +250,12 @@ function buildPanelContent(host: InspectorHost, asset: TilemapAsset): void {
else layerName.setValue(paintedName);
},
});
const layerZField = new NumberField(paintedLayer ? layerZ(paintedLayer) : 0, {
onChange: (z) => {
if (paintedLayer && z !== layerZ(paintedLayer))
state.execute(new SetTilemapLayerZCommand(asset.id, painted, z));
},
});
const focus: Dropdown = new Dropdown(FOCUS.find((f) => f.focus === paint.focus)?.label ?? '', {
onClick: () =>
new Menu(
@@ -259,6 +270,7 @@ function buildPanelContent(host: InspectorHost, asset: TilemapAsset): void {
palette: null,
layers: [],
layerName,
layerZ: layerZField,
focus,
addLayer: new Button('Add layer', {
onClick: () => state.execute(new AddTilemapLayerCommand(asset.id)),
@@ -326,6 +338,10 @@ function buildPanelContent(host: InspectorHost, asset: TilemapAsset): void {
const nameRow = labelledRow('Name').row;
nameRow.add(layerName, 1);
host.body.add(nameRow);
const zRow = labelledRow('Z').row;
zRow.add(layerZField, 1);
host.body.add(zRow);
addNote(host, 'Added to the map’s own Z, as a child’s is.', 'small');
const showRow = labelledRow('Show').row;
showRow.add(focus, 1);
host.body.add(showRow);
@@ -346,7 +362,9 @@ function tileIdsOf(state: EditorState): string[] {
*/
function tilemapSignature(state: EditorState, asset: TilemapAsset): string {
const paint = state.tilemapPaint;
const layers = asset.layers.map((l) => `${l.id}:${l.name}:${isLayerVisible(l) ? 1 : 0}`).join(',');
const layers = asset.layers
.map((l) => `${l.id}:${l.name}:${isLayerVisible(l) ? 1 : 0}:${layerZ(l)}`)
.join(',');
const tiles = tileIdsOf(state).join(',');
return `${paint.tool}|${paint.tileId}|${paintedLayerId(state, asset)}|${paint.focus}|${layers}|${tiles}`;
}