Tilemaps are a new placeable asset type that is painted with autotiles in the scene view, with layers, brush, eraser and rectangle, and is drawn at runtime and in the export (#128)
game-maker / gate (push) Successful in 1m38s
game-maker / suite (push) Successful in 5m51s

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-18 06:41:47 +02:00
1 parent 0607221423
commit 33a7b1b63e
30 files changed
+2060 -20

No files matched your search

+31 -1
View File
@@ -19,7 +19,15 @@ import {
import { isParticleNodeDef } from '../particles/nodes';
import { isShaderNodeDef } from '../shader/nodes';
import { isKeyInterpolation, normalizeKeys } from '../model/animation';
import type { AnimationKey, AnimationTrack, Asset, StateMachineAsset, TextureFrame } from '../model/Asset';
import type {
AnimationKey,
AnimationTrack,
Asset,
StateMachineAsset,
TextureFrame,
TilemapLayer,
} from '../model/Asset';
import { parseCellKey } from '../model/tilemap';
import { isAssetType } from '../model/AssetTypes';
import { isFontFile } from '../model/font';
import { isSoundFile } from '../model/sound';
@@ -175,6 +183,8 @@ export function deserializeProject(raw: unknown, fallbackId = ''): Project {
(id): id is string => typeof id === 'string' && id !== '',
);
assets.push({ id, type, name, props, pictures });
} else if (type === 'tilemap') {
assets.push({ id, type, name, props, layers: normalizeLayers(a.layers) });
} else if (type === 'animation') {
// A root or row aiming at something gone is kept: it reads as missing and keeps its keys.
const root = typeof a.root === 'string' ? a.root : '';
@@ -493,6 +503,26 @@ function normalizeTracks(raw: unknown): AnimationTrack[] {
return tracks;
}
/**
* The layers of a tilemap. A cell whose key is not a pair of whole numbers, or which names nothing,
* is dropped; one naming a deleted autotile is kept, like an animation's dangling row, so an undo
* brings the drawing back. A doubled layer id is dropped as a doubled node is.
*/
function normalizeLayers(raw: unknown): TilemapLayer[] {
const layers: TilemapLayer[] = [];
for (const item of Array.isArray(raw) ? raw : []) {
const l = asRecord(item);
if (typeof l.id !== 'string' || !l.id || layers.some((o) => o.id === l.id)) continue;
const cells: Record<string, string> = {};
for (const [key, value] of Object.entries(asRecord(l.cells)))
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;
layers.push(layer);
}
return layers;
}
function normalizeBag(raw: unknown, schema: PropertySchema, sparse: boolean): PropertyBag {
const r = asRecord(raw);
const bag: PropertyBag = {};