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)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5385d9e152
commit
47eea2f6e4
13 files changed
+389
-38
No files matched your search
@@ -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}`;
|
||||
}
|
||||
Reference in new issue
Block a user