@yagejs/tilemap 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -77,6 +77,7 @@ __export(index_exports, {
77
77
  resolveObjectRefArray: () => resolveObjectRefArray,
78
78
  tiledMap: () => tiledMap,
79
79
  tiledMapAssetExtension: () => tiledMapAssetExtension,
80
+ tiledObjectKey: () => tiledObjectKey,
80
81
  toPhysicsColliders: () => toPhysicsColliders,
81
82
  toTilemapData: () => toTilemapData
82
83
  });
@@ -350,6 +351,48 @@ function objectToColliderConfig(obj) {
350
351
  }
351
352
  __name(objectToColliderConfig, "objectToColliderConfig");
352
353
 
354
+ // src/keys.ts
355
+ function tiledObjectKey(prefix, objectId) {
356
+ return `${prefix}#object:${objectId}`;
357
+ }
358
+ __name(tiledObjectKey, "tiledObjectKey");
359
+
360
+ // src/properties.ts
361
+ function getProperty(obj, name) {
362
+ const prop = obj.properties?.find((p) => p.name === name);
363
+ return prop?.value;
364
+ }
365
+ __name(getProperty, "getProperty");
366
+ function getPropertyArray(obj, name) {
367
+ const pattern = new RegExp(`^${escapeRegex(name)}\\[(\\d+)\\]$`);
368
+ const values = [];
369
+ if (!obj.properties) return values;
370
+ for (const prop of obj.properties) {
371
+ const match = prop.name.match(pattern);
372
+ if (match) {
373
+ const index = Number.parseInt(match[1], 10);
374
+ values[index] = prop.value;
375
+ }
376
+ }
377
+ return values;
378
+ }
379
+ __name(getPropertyArray, "getPropertyArray");
380
+ function resolveObjectRef(obj, propName, allObjects) {
381
+ const id = getProperty(obj, propName);
382
+ if (id === void 0) return void 0;
383
+ return allObjects.find((o) => o.id === id);
384
+ }
385
+ __name(resolveObjectRef, "resolveObjectRef");
386
+ function resolveObjectRefArray(obj, propName, allObjects) {
387
+ const ids = getPropertyArray(obj, propName);
388
+ return ids.map((id) => allObjects.find((o) => o.id === id)).filter((o) => o !== void 0);
389
+ }
390
+ __name(resolveObjectRefArray, "resolveObjectRefArray");
391
+ function escapeRegex(str) {
392
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
393
+ }
394
+ __name(escapeRegex, "escapeRegex");
395
+
353
396
  // src/TilemapComponent.ts
354
397
  var _TilemapComponent_decorators, _init, _a;
355
398
  _TilemapComponent_decorators = [import_core.serializable];
@@ -359,28 +402,51 @@ var _TilemapComponent = class _TilemapComponent extends (_a = import_core.Compon
359
402
  }
360
403
  container;
361
404
  data;
405
+ /** Asset path of this map, or `null` if constructed from a raw `TiledMapData` without one. */
406
+ mapKey;
407
+ /** Prefix used to derive auto-keys for entities spawned from objects. */
408
+ keyPrefix;
362
409
  _tiledMap;
363
- _mapKey;
364
410
  layerNames;
365
411
  renderLayerName;
412
+ _explicitKeyPrefix;
413
+ /** Lazy flat-list cache. The parsed map is treated as immutable post-construction; if that ever changes, callers must invalidate. */
414
+ _allObjectsCache;
366
415
  constructor(options) {
367
416
  super();
368
- if (!options.map && !options.mapKey) {
417
+ const sourceCount = (options.source ? 1 : 0) + (options.map ? 1 : 0) + (options.mapKey ? 1 : 0);
418
+ if (sourceCount === 0) {
369
419
  throw new Error(
370
- "TilemapComponent requires either `map` or `mapKey`."
420
+ "TilemapComponent requires one of `source`, `map`, or `mapKey`."
371
421
  );
372
422
  }
373
- this._mapKey = options.mapKey ?? null;
374
- const tiledMap2 = options.map ?? import_pixi3.Assets.get(options.mapKey);
375
- if (!tiledMap2) {
376
- throw new Error(
377
- `TilemapComponent: map "${options.mapKey}" is not loaded. Add it to scene preload.`
378
- );
423
+ if (options.source) {
424
+ this.mapKey = options.source.path;
425
+ const data = import_pixi3.Assets.get(options.source.path);
426
+ if (!data) {
427
+ throw new Error(
428
+ `TilemapComponent: source "${options.source.path}" is not loaded. Add it to scene preload.`
429
+ );
430
+ }
431
+ this._tiledMap = data;
432
+ } else if (options.mapKey) {
433
+ this.mapKey = options.mapKey;
434
+ const data = import_pixi3.Assets.get(options.mapKey);
435
+ if (!data) {
436
+ throw new Error(
437
+ `TilemapComponent: map "${options.mapKey}" is not loaded. Add it to scene preload.`
438
+ );
439
+ }
440
+ this._tiledMap = data;
441
+ } else {
442
+ this.mapKey = null;
443
+ this._tiledMap = options.map;
379
444
  }
380
- this._tiledMap = tiledMap2;
381
- this.data = toTilemapData(tiledMap2);
445
+ this.data = toTilemapData(this._tiledMap);
382
446
  this.layerNames = options.layers;
383
447
  this.renderLayerName = options.layer ?? "default";
448
+ this._explicitKeyPrefix = options.keyPrefix;
449
+ this.keyPrefix = options.keyPrefix ?? this.mapKey;
384
450
  this.container = new import_pixi3.Container();
385
451
  }
386
452
  onAdd() {
@@ -396,23 +462,27 @@ var _TilemapComponent = class _TilemapComponent extends (_a = import_core.Compon
396
462
  this.container.destroy({ children: true });
397
463
  }
398
464
  serialize() {
399
- if (!this._mapKey) {
465
+ if (!this.mapKey) {
400
466
  console.warn(
401
- `TilemapComponent on "${this.entity?.name}": created with a TiledMapData object. Use { mapKey } for save/load support.`
467
+ `TilemapComponent on "${this.entity?.name}": created with a TiledMapData object. Use { source } or { mapKey } for save/load support.`
402
468
  );
403
469
  return null;
404
470
  }
405
471
  return {
406
- mapKey: this._mapKey,
472
+ mapKey: this.mapKey,
407
473
  layer: this.renderLayerName,
408
- ...this.layerNames && { layers: this.layerNames }
474
+ ...this.layerNames && { layers: this.layerNames },
475
+ ...this._explicitKeyPrefix !== void 0 && {
476
+ keyPrefix: this._explicitKeyPrefix
477
+ }
409
478
  };
410
479
  }
411
480
  static fromSnapshot(data) {
412
481
  return new _TilemapComponent({
413
482
  mapKey: data.mapKey,
414
483
  layer: data.layer,
415
- ...data.layers && { layers: data.layers }
484
+ ...data.layers && { layers: data.layers },
485
+ ...data.keyPrefix !== void 0 && { keyPrefix: data.keyPrefix }
416
486
  });
417
487
  }
418
488
  /** Map width in pixels. */
@@ -457,7 +527,7 @@ var _TilemapComponent = class _TilemapComponent extends (_a = import_core.Compon
457
527
  getCollisionShapes(objectLayerName) {
458
528
  return extractCollisionShapes(this.data, objectLayerName);
459
529
  }
460
- /** Extract objects from object layers grouped by class/name. */
530
+ /** Objects from object layers grouped by `class ?? name`. Use a layer name to scope. */
461
531
  getObjects(objectLayerName) {
462
532
  const filtered = objectLayerName ? this.data.objectLayers.filter((l) => l.name === objectLayerName) : this.data.objectLayers;
463
533
  const result = {};
@@ -472,6 +542,84 @@ var _TilemapComponent = class _TilemapComponent extends (_a = import_core.Compon
472
542
  }
473
543
  return result;
474
544
  }
545
+ /** Flat list of every object across every object layer. Memoized — safe because parsed map data is immutable post-construction. */
546
+ getAllObjects() {
547
+ if (this._allObjectsCache) return this._allObjectsCache;
548
+ const result = [];
549
+ for (const layer of this.data.objectLayers) {
550
+ for (const obj of layer.objects) result.push(obj);
551
+ }
552
+ this._allObjectsCache = result;
553
+ return result;
554
+ }
555
+ /**
556
+ * Iterate every object on the given layer (or every layer if omitted),
557
+ * passing the auto-derived stable key alongside each object so callers can
558
+ * spawn entities with `scene.spawn(Class, params, { key })`.
559
+ *
560
+ * Skips objects that don't have a key prefix (component constructed from raw
561
+ * `map:` without `mapKey` or `keyPrefix`) — those callers should iterate
562
+ * `getObjects` directly.
563
+ */
564
+ forEachObject(layerName, fn) {
565
+ if (this.keyPrefix === null) {
566
+ throw new Error(
567
+ "TilemapComponent.forEachObject: cannot derive auto-keys without a `mapKey`, `source`, or explicit `keyPrefix`."
568
+ );
569
+ }
570
+ const layers = layerName ? this.data.objectLayers.filter((l) => l.name === layerName) : this.data.objectLayers;
571
+ for (const layer of layers) {
572
+ for (const obj of layer.objects) {
573
+ fn(obj, tiledObjectKey(this.keyPrefix, obj.id));
574
+ }
575
+ }
576
+ }
577
+ /** Auto-derived stable key for an object: `<keyPrefix>#object:<id>`. */
578
+ objectKey(obj) {
579
+ if (this.keyPrefix === null) {
580
+ throw new Error(
581
+ "TilemapComponent.objectKey: cannot derive a key without a `mapKey`, `source`, or explicit `keyPrefix`."
582
+ );
583
+ }
584
+ return tiledObjectKey(this.keyPrefix, obj.id);
585
+ }
586
+ /** Find an object by its Tiled `id`. Searches every object layer. */
587
+ findObject(id) {
588
+ for (const layer of this.data.objectLayers) {
589
+ for (const obj of layer.objects) {
590
+ if (obj.id === id) return obj;
591
+ }
592
+ }
593
+ return void 0;
594
+ }
595
+ /** Find the first object with a matching `name`. Searches every object layer. */
596
+ findObjectByName(name) {
597
+ for (const layer of this.data.objectLayers) {
598
+ for (const obj of layer.objects) {
599
+ if (obj.name === name) return obj;
600
+ }
601
+ }
602
+ return void 0;
603
+ }
604
+ /** Read a typed custom property off any tilemap object. */
605
+ getProperty(obj, name) {
606
+ return getProperty(obj, name);
607
+ }
608
+ /** Read an indexed property bag (`name[0]`, `name[1]`, ...) as an array. */
609
+ getPropertyArray(obj, name) {
610
+ return getPropertyArray(obj, name);
611
+ }
612
+ /**
613
+ * Resolve a Tiled object-reference property to the actual object.
614
+ * Auto-collects across every layer so callers don't have to.
615
+ */
616
+ resolveRef(obj, propName) {
617
+ return resolveObjectRef(obj, propName, this.getAllObjects());
618
+ }
619
+ /** Same as `resolveRef`, but for indexed object-reference arrays. */
620
+ resolveRefArray(obj, propName) {
621
+ return resolveObjectRefArray(obj, propName, this.getAllObjects());
622
+ }
475
623
  };
476
624
  _init = __decoratorStart(_a);
477
625
  _TilemapComponent = __decorateElement(_init, 0, "TilemapComponent", _TilemapComponent_decorators, _TilemapComponent);
@@ -561,42 +709,6 @@ function toPhysicsCollider(config) {
561
709
  }
562
710
  }
563
711
  __name(toPhysicsCollider, "toPhysicsCollider");
564
-
565
- // src/properties.ts
566
- function getProperty(obj, name) {
567
- const prop = obj.properties?.find((p) => p.name === name);
568
- return prop?.value;
569
- }
570
- __name(getProperty, "getProperty");
571
- function getPropertyArray(obj, name) {
572
- const pattern = new RegExp(`^${escapeRegex(name)}\\[(\\d+)\\]$`);
573
- const values = [];
574
- if (!obj.properties) return values;
575
- for (const prop of obj.properties) {
576
- const match = prop.name.match(pattern);
577
- if (match) {
578
- const index = Number.parseInt(match[1], 10);
579
- values[index] = prop.value;
580
- }
581
- }
582
- return values;
583
- }
584
- __name(getPropertyArray, "getPropertyArray");
585
- function resolveObjectRef(obj, propName, allObjects) {
586
- const id = getProperty(obj, propName);
587
- if (id === void 0) return void 0;
588
- return allObjects.find((o) => o.id === id);
589
- }
590
- __name(resolveObjectRef, "resolveObjectRef");
591
- function resolveObjectRefArray(obj, propName, allObjects) {
592
- const ids = getPropertyArray(obj, propName);
593
- return ids.map((id) => allObjects.find((o) => o.id === id)).filter((o) => o !== void 0);
594
- }
595
- __name(resolveObjectRefArray, "resolveObjectRefArray");
596
- function escapeRegex(str) {
597
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
598
- }
599
- __name(escapeRegex, "escapeRegex");
600
712
  // Annotate the CommonJS export names for ESM import in node:
601
713
  0 && (module.exports = {
602
714
  TilemapComponent,
@@ -611,6 +723,7 @@ __name(escapeRegex, "escapeRegex");
611
723
  resolveObjectRefArray,
612
724
  tiledMap,
613
725
  tiledMapAssetExtension,
726
+ tiledObjectKey,
614
727
  toPhysicsColliders,
615
728
  toTilemapData
616
729
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/TilemapPlugin.ts","../src/tiled/tiledMapLoader.ts","../src/TilemapRenderSystem.ts","../src/TilemapComponent.ts","../src/tiled/parseTiledMap.ts","../src/colliders.ts","../src/assets.ts","../src/toPhysicsColliders.ts","../src/properties.ts"],"sourcesContent":["// Plugin\nexport { TilemapPlugin } from \"./TilemapPlugin.js\";\n\n// Component\nexport { TilemapComponent } from \"./TilemapComponent.js\";\nexport type {\n TilemapComponentOptions,\n TilemapComponentData,\n} from \"./TilemapComponent.js\";\n\n// System\nexport { TilemapRenderSystem } from \"./TilemapRenderSystem.js\";\n\n// Asset handle factory\nexport { tiledMap } from \"./assets.js\";\n\n// Collision extraction\nexport { extractCollisionShapes } from \"./colliders.js\";\nexport { toPhysicsColliders } from \"./toPhysicsColliders.js\";\n\n// Property utilities\nexport {\n getProperty,\n getPropertyArray,\n resolveObjectRef,\n resolveObjectRefArray,\n} from \"./properties.js\";\n\n// Generic types\nexport type {\n TilemapData,\n TileLayerData,\n ObjectLayerData,\n MapObject,\n MapObjectProperty,\n HasProperties,\n TilemapColliderConfig,\n RectColliderConfig,\n PolygonColliderConfig,\n} from \"./types.js\";\n\n// Tiled-specific (re-exported for backward compatibility)\nexport { tiledMapAssetExtension } from \"./tiled/tiledMapLoader.js\";\nexport {\n createTilemapLayers,\n extractObjects,\n toTilemapData,\n} from \"./tiled/parseTiledMap.js\";\nexport type {\n TiledMapData,\n TileLayer,\n ObjectGroup,\n TileObject,\n RectangleObject,\n PolygonObject,\n PointObject,\n TileObjectProperty,\n TilesetRef,\n TilesetData,\n TileData,\n} from \"./tiled/types.js\";\n","import { AssetManagerKey } from \"@yagejs/core\";\nimport type { EngineContext, Plugin, SystemScheduler } from \"@yagejs/core\";\nimport { extensions, Assets } from \"pixi.js\";\nimport { tiledMapAssetExtension } from \"./tiled/tiledMapLoader.js\";\nimport { TilemapRenderSystem } from \"./TilemapRenderSystem.js\";\nimport type { TiledMapData } from \"./tiled/types.js\";\n\n/** Plugin that adds Tiled map loading and rendering to YAGE. */\nexport class TilemapPlugin implements Plugin {\n readonly name = \"tilemap\";\n readonly version = \"2.0.0\";\n readonly dependencies = [\"renderer\"] as const;\n\n install(context: EngineContext): void {\n // Register PixiJS loader extension for Tiled map JSON files\n extensions.add(tiledMapAssetExtension);\n\n // Register \"tiledMap\" loader with AssetManager\n const am = context.tryResolve(AssetManagerKey);\n am?.registerLoader(\"tiledMap\", {\n load: (path: string) => Assets.load<TiledMapData>(path),\n unload: (path: string) => {\n Assets.unload(path);\n },\n });\n }\n\n registerSystems(scheduler: SystemScheduler): void {\n scheduler.add(new TilemapRenderSystem());\n }\n}\n","import {\n ExtensionType,\n LoaderParserPriority,\n Assets,\n path,\n Texture,\n Rectangle,\n} from \"pixi.js\";\nimport type { LoaderParser, ResolvedAsset, Loader } from \"pixi.js\";\nimport type { TiledMapData, TilesetData, TilesetRef } from \"./types.js\";\n\n/**\n * PixiJS loader extension that detects Tiled map JSON files and resolves\n * their tileset references.\n *\n * Supports two tileset formats:\n * 1. **Collection-of-images** — tileset has `tiles[]` with image paths.\n * Assumes textures are already in the PixiJS cache (e.g. from a\n * pre-loaded spritesheet atlas).\n * 2. **Single-image tileset** — tileset has an `image` property pointing\n * to a spritesheet. The loader loads the image and creates sub-textures\n * for each tile based on grid layout.\n */\nconst tiledMapLoaderParser: LoaderParser<TiledMapData> = {\n id: \"tiledMapLoader\",\n\n extension: {\n type: ExtensionType.LoadParser,\n priority: LoaderParserPriority.High,\n },\n\n async testParse(\n asset: TiledMapData,\n resolvedAsset?: ResolvedAsset,\n ): Promise<boolean> {\n if (!resolvedAsset?.src) return false;\n if (path.extname(resolvedAsset.src).toLowerCase() !== \".json\") return false;\n const obj = asset as unknown as Record<string, unknown>;\n return !!(obj.tilesets && obj.layers);\n },\n\n async parse(\n asset: TiledMapData,\n resolvedAsset?: ResolvedAsset,\n loader?: Loader,\n ): Promise<TiledMapData> {\n const src = resolvedAsset?.src;\n if (!src || !loader) return asset;\n\n let basePath = path.dirname(src);\n if (basePath && !basePath.endsWith(\"/\")) {\n basePath += \"/\";\n }\n\n for (const tilesetRef of asset.tilesets as TilesetRef[]) {\n if (tilesetRef.source) {\n // External tileset JSON — load it\n const tilesetPath = basePath + tilesetRef.source;\n const tilesetData = (await loader.load<TilesetData>({\n src: tilesetPath,\n })) as TilesetData;\n tilesetRef.data = tilesetData;\n }\n\n const tileset = tilesetRef.data;\n if (!tileset) continue;\n\n // Single-image tileset: load the image and create sub-textures\n if (tileset.image && !tileset.tiles?.length) {\n const imagePath = basePath + tileset.image;\n const baseTexture = await Assets.load<Texture>(imagePath);\n const cols = tileset.columns;\n const tw = tileset.tilewidth;\n const th = tileset.tileheight;\n const margin = tileset.margin ?? 0;\n const spacing = tileset.spacing ?? 0;\n\n for (let id = 0; id < tileset.tilecount; id++) {\n const col = id % cols;\n const row = Math.floor(id / cols);\n const x = margin + col * (tw + spacing);\n const y = margin + row * (th + spacing);\n\n const frame = new Rectangle(x, y, tw, th);\n const subtex = new Texture({\n source: baseTexture.source,\n frame,\n });\n\n // Store subtexture in PixiJS cache with a key like \"tileset-name:id\"\n const cacheKey = `${tileset.name}:${id}`;\n Assets.cache.set(cacheKey, subtex);\n }\n }\n // Collection-of-images: textures are expected to already be\n // in the PixiJS cache (loaded via spritesheet atlas).\n }\n\n return asset;\n },\n\n unload() {},\n};\n\n/** PixiJS asset extension bundle for Tiled map JSON files. */\nexport const tiledMapAssetExtension = {\n extension: ExtensionType.Asset,\n loader: tiledMapLoaderParser,\n};\n","import { System, Phase, Transform, QueryCacheKey } from \"@yagejs/core\";\nimport type { EngineContext, QueryResult } from \"@yagejs/core\";\nimport { TilemapComponent } from \"./TilemapComponent.js\";\n\n/** Syncs Transform to TilemapComponent display containers. */\nexport class TilemapRenderSystem extends System {\n readonly phase = Phase.Render;\n readonly priority = -1; // Before DisplaySystem (0), so tilemaps render behind sprites\n\n private query!: QueryResult;\n\n onRegister(context: EngineContext): void {\n const queryCache = context.resolve(QueryCacheKey);\n this.query = queryCache.register([Transform, TilemapComponent]);\n }\n\n update(): void {\n for (const entity of this.query) {\n const transform = entity.get(Transform);\n const tilemap = entity.get(TilemapComponent);\n if (!tilemap.enabled) continue;\n\n tilemap.container.position.x = transform.worldPosition.x;\n tilemap.container.position.y = transform.worldPosition.y;\n tilemap.container.rotation = transform.worldRotation;\n tilemap.container.scale.x = transform.worldScale.x;\n tilemap.container.scale.y = transform.worldScale.y;\n }\n }\n}\n","import { Component, Transform, serializable } from \"@yagejs/core\";\nimport { Assets, Container } from \"pixi.js\";\nimport { SceneRenderTreeKey } from \"@yagejs/renderer\";\nimport { createTilemapLayers, toTilemapData } from \"./tiled/parseTiledMap.js\";\nimport { extractCollisionShapes } from \"./colliders.js\";\nimport type { TiledMapData } from \"./tiled/types.js\";\nimport type {\n TilemapData,\n MapObject,\n TilemapColliderConfig,\n} from \"./types.js\";\n\n/** Options for creating a TilemapComponent. */\nexport interface TilemapComponentOptions {\n /** Parsed Tiled map data (not serializable). */\n map?: TiledMapData;\n /** Asset path to the Tiled JSON (serializable, resolved via Assets.get). */\n mapKey?: string;\n /** Which tile layers to render. Omit to render all. */\n layers?: string[];\n /** Render layer name. Default: \"default\". */\n layer?: string;\n}\n\n/** Serializable snapshot of a TilemapComponent. */\nexport interface TilemapComponentData {\n mapKey: string;\n layers?: string[];\n layer: string;\n}\n\n/** Component that renders a Tiled map using @pixi/tilemap. */\n@serializable\nexport class TilemapComponent extends Component {\n readonly container: Container;\n readonly data: TilemapData;\n private readonly _tiledMap: TiledMapData;\n private readonly _mapKey: string | null;\n private readonly layerNames: string[] | undefined;\n private readonly renderLayerName: string;\n\n constructor(options: TilemapComponentOptions) {\n super();\n\n if (!options.map && !options.mapKey) {\n throw new Error(\n \"TilemapComponent requires either `map` or `mapKey`.\",\n );\n }\n\n this._mapKey = options.mapKey ?? null;\n const tiledMap = options.map ?? Assets.get<TiledMapData>(options.mapKey!);\n if (!tiledMap) {\n throw new Error(\n `TilemapComponent: map \"${options.mapKey}\" is not loaded. Add it to scene preload.`,\n );\n }\n\n this._tiledMap = tiledMap;\n this.data = toTilemapData(tiledMap);\n this.layerNames = options.layers;\n this.renderLayerName = options.layer ?? \"default\";\n this.container = new Container();\n }\n\n onAdd(): void {\n const tilemapLayers = createTilemapLayers(this._tiledMap, this.layerNames);\n for (const layer of tilemapLayers) {\n this.container.addChild(layer);\n }\n\n const renderLayer = this.use(SceneRenderTreeKey).get(this.renderLayerName);\n renderLayer.container.addChild(this.container);\n }\n\n onDestroy(): void {\n this.container.removeFromParent();\n this.container.destroy({ children: true });\n }\n\n serialize(): TilemapComponentData | null {\n if (!this._mapKey) {\n console.warn(\n `TilemapComponent on \"${this.entity?.name}\": created with a TiledMapData object. ` +\n `Use { mapKey } for save/load support.`,\n );\n return null;\n }\n return {\n mapKey: this._mapKey,\n layer: this.renderLayerName,\n ...(this.layerNames && { layers: this.layerNames }),\n };\n }\n\n static fromSnapshot(data: TilemapComponentData): TilemapComponent {\n return new TilemapComponent({\n mapKey: data.mapKey,\n layer: data.layer,\n ...(data.layers && { layers: data.layers }),\n });\n }\n\n /** Map width in pixels. */\n get widthPx(): number {\n return this.data.width * this.data.tileWidth;\n }\n\n /** Map height in pixels. */\n get heightPx(): number {\n return this.data.height * this.data.tileHeight;\n }\n\n /** Tile width in pixels. */\n get tileWidth(): number {\n return this.data.tileWidth;\n }\n\n /** Tile height in pixels. */\n get tileHeight(): number {\n return this.data.tileHeight;\n }\n\n /**\n * Returns the tile GID at a world position, accounting for entity Transform offset.\n * Returns null if the position is outside the map or the tile is empty.\n */\n getTileAt(\n worldX: number,\n worldY: number,\n layerName?: string,\n ): number | null {\n const transform = this.entity.tryGet(Transform);\n const offsetX = transform ? transform.position.x : 0;\n const offsetY = transform ? transform.position.y : 0;\n const localX = worldX - offsetX;\n const localY = worldY - offsetY;\n\n const col = Math.floor(localX / this.data.tileWidth);\n const row = Math.floor(localY / this.data.tileHeight);\n\n if (col < 0 || col >= this.data.width) return null;\n if (row < 0 || row >= this.data.height) return null;\n\n const layers = layerName\n ? this.data.tileLayers.filter((l) => l.name === layerName)\n : this.data.tileLayers;\n\n // Return first non-zero GID found (from last layer to first for top-most)\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i]!;\n const gid = layer.data[row * layer.width + col];\n if (gid !== undefined && gid !== 0) return gid;\n }\n\n return null;\n }\n\n /** Extract physics-agnostic collision shapes from object layers. */\n getCollisionShapes(objectLayerName?: string): TilemapColliderConfig[] {\n return extractCollisionShapes(this.data, objectLayerName);\n }\n\n /** Extract objects from object layers grouped by class/name. */\n getObjects(objectLayerName?: string): Record<string, MapObject[]> {\n const filtered = objectLayerName\n ? this.data.objectLayers.filter((l) => l.name === objectLayerName)\n : this.data.objectLayers;\n\n const result: Record<string, MapObject[]> = {};\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const key = obj.class ?? obj.name;\n if (!result[key]) {\n result[key] = [];\n }\n result[key].push(obj);\n }\n }\n\n return result;\n }\n}\n","import { CompositeTilemap } from \"@pixi/tilemap\";\nimport { Assets, Texture, Rectangle } from \"pixi.js\";\nimport type {\n TiledMapData,\n TileLayer,\n TilesetRef,\n ObjectGroup,\n TileObject,\n} from \"./types.js\";\nimport type {\n TilemapData,\n TileLayerData,\n ObjectLayerData,\n MapObject,\n} from \"../types.js\";\n\n// ─── Generic adapter ────────────────────────────────────────────────\n\n/**\n * Convert Tiled JSON data to the generic TilemapData format.\n */\nexport function toTilemapData(map: TiledMapData): TilemapData {\n const tileLayers: TileLayerData[] = [];\n const objectLayers: ObjectLayerData[] = [];\n\n for (const layer of map.layers) {\n if (layer.type === \"tilelayer\") {\n tileLayers.push({\n name: layer.name,\n data: layer.data,\n width: layer.width,\n height: layer.height,\n visible: layer.visible,\n });\n } else if (layer.type === \"objectgroup\") {\n objectLayers.push({\n name: layer.name,\n objects: layer.objects.map(tiledObjectToMapObject),\n visible: layer.visible,\n });\n }\n }\n\n return {\n width: map.width,\n height: map.height,\n tileWidth: map.tilewidth,\n tileHeight: map.tileheight,\n tileLayers,\n objectLayers,\n };\n}\n\nfunction tiledObjectToMapObject(obj: TileObject): MapObject {\n const result: MapObject = {\n id: obj.id,\n name: obj.name,\n x: obj.x,\n y: obj.y,\n width: obj.width,\n height: obj.height,\n rotation: obj.rotation,\n visible: obj.visible,\n };\n\n const cls = obj.class ?? obj.type;\n if (cls) result.class = cls;\n if (obj.point === true) result.point = true;\n if (obj.polygon) result.polygon = obj.polygon;\n if (obj.properties) {\n result.properties = obj.properties.map((p) => ({\n name: p.name,\n type: p.type,\n value: p.value,\n }));\n }\n\n return result;\n}\n\n// ─── Tiled-specific rendering ───────────────────────────────────────\n\n/**\n * Resolve the tileset that owns a given global tile ID.\n * Tilesets are sorted by firstgid; we find the last tileset whose firstgid <= gid.\n */\nfunction findTileset(tilesets: TilesetRef[], gid: number): TilesetRef | null {\n let result: TilesetRef | null = null;\n for (const ts of tilesets) {\n if (ts.firstgid <= gid) {\n if (!result || ts.firstgid > result.firstgid) {\n result = ts;\n }\n }\n }\n return result;\n}\n\n/**\n * Resolve the texture for a tile given its GID and owning tileset.\n */\nfunction resolveTileTexture(\n gid: number,\n tileset: TilesetRef,\n): Texture | null {\n const data = tileset.data;\n if (!data) return null;\n const localId = gid - tileset.firstgid;\n\n if (data.tiles?.length) {\n // Collection-of-images tileset: look up texture by filename from cache\n const tileData = data.tiles[localId];\n if (!tileData?.image) return null;\n const filenameMatch = tileData.image.match(/[^/]*$/);\n const filename = filenameMatch?.[0];\n if (!filename) return null;\n const tex = Assets.get<Texture>(filename);\n return tex ?? null;\n }\n\n if (data.image) {\n // Single-image tileset: sub-textures were created by the loader\n const cacheKey = `${data.name}:${localId}`;\n const tex = Assets.get<Texture>(cacheKey);\n if (tex) return tex;\n\n // Fallback: create sub-texture on the fly from the base image\n const filenameMatch = data.image.match(/[^/]*$/);\n const filename = filenameMatch?.[0];\n if (!filename) return null;\n const baseTex = Assets.get<Texture>(filename);\n if (!baseTex) return null;\n\n const cols = data.columns;\n const tw = data.tilewidth;\n const th = data.tileheight;\n const margin = data.margin ?? 0;\n const spacing = data.spacing ?? 0;\n const col = localId % cols;\n const row = Math.floor(localId / cols);\n const x = margin + col * (tw + spacing);\n const y = margin + row * (th + spacing);\n\n return new Texture({\n source: baseTex.source,\n frame: new Rectangle(x, y, tw, th),\n });\n }\n\n return null;\n}\n\n/**\n * Build CompositeTilemap display objects from a parsed Tiled map.\n *\n * @param map - Parsed TiledMapData (with resolved tilesets).\n * @param layerNames - Optional filter: only process these tile layer names.\n * @returns Array of CompositeTilemap, one per tile layer.\n */\nexport function createTilemapLayers(\n map: TiledMapData,\n layerNames?: string[],\n): CompositeTilemap[] {\n const tileLayers = map.layers.filter(\n (l): l is TileLayer => l.type === \"tilelayer\",\n );\n\n const filtered = layerNames\n ? tileLayers.filter((l) => layerNames.includes(l.name))\n : tileLayers;\n\n return filtered.map((layer) => {\n const tilemap = new CompositeTilemap();\n const { data, width } = layer;\n\n for (let index = 0; index < data.length; index++) {\n const gid = data[index]!;\n if (gid === 0) continue;\n\n const tileset = findTileset(map.tilesets, gid);\n if (!tileset) {\n throw new Error(`No tileset found for tile GID ${gid}`);\n }\n\n const texture = resolveTileTexture(gid, tileset);\n if (!texture) {\n throw new Error(\n `Could not resolve texture for tile GID ${gid} in tileset \"${tileset.data?.name}\"`,\n );\n }\n\n const x = index % width;\n const y = Math.floor(index / width);\n tilemap.tile(texture, x * map.tilewidth, y * map.tileheight);\n }\n\n return tilemap;\n });\n}\n\n/**\n * Extract objects from Tiled object layers, grouped by class/type/name.\n *\n * @param map - Parsed TiledMapData.\n * @param objectLayerName - Optional: only extract from this layer.\n * @returns Record mapping class/type/name to arrays of TileObject.\n */\nexport function extractObjects(\n map: TiledMapData,\n objectLayerName?: string,\n): Record<string, TileObject[]> {\n const objectLayers = map.layers.filter(\n (l): l is ObjectGroup => l.type === \"objectgroup\",\n );\n\n const filtered = objectLayerName\n ? objectLayers.filter((l) => l.name === objectLayerName)\n : objectLayers;\n\n const result: Record<string, TileObject[]> = {};\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const key = obj.class ?? obj.type ?? obj.name;\n if (!result[key]) {\n result[key] = [];\n }\n result[key].push(obj);\n }\n }\n\n return result;\n}\n","import type {\n TilemapData,\n MapObject,\n TilemapColliderConfig,\n RectColliderConfig,\n PolygonColliderConfig,\n} from \"./types.js\";\n\n/**\n * Extract physics-agnostic collision shapes from object layers.\n *\n * - Rectangle objects -> RectColliderConfig\n * - Polygon objects -> PolygonColliderConfig\n * - Point objects -> skipped (not collision shapes)\n *\n * @param map - Generic TilemapData.\n * @param objectLayerName - Optional: only extract from this layer.\n */\nexport function extractCollisionShapes(\n map: TilemapData,\n objectLayerName?: string,\n): TilemapColliderConfig[] {\n const filtered = objectLayerName\n ? map.objectLayers.filter((l) => l.name === objectLayerName)\n : map.objectLayers;\n\n const shapes: TilemapColliderConfig[] = [];\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const shape = objectToColliderConfig(obj);\n if (shape) shapes.push(shape);\n }\n }\n\n return shapes;\n}\n\n/**\n * Convert a single MapObject to a ColliderConfig.\n * Returns null for point objects (not collision shapes).\n */\nfunction objectToColliderConfig(obj: MapObject): TilemapColliderConfig | null {\n // Skip point objects\n if (obj.point) return null;\n\n if (obj.polygon) {\n const config: PolygonColliderConfig = {\n type: \"polygon\",\n x: obj.x,\n y: obj.y,\n vertices: obj.polygon.map((v) => ({ x: v.x, y: v.y })),\n };\n return config;\n }\n\n // Rectangle object\n const config: RectColliderConfig = {\n type: \"rect\",\n x: obj.x,\n y: obj.y,\n width: obj.width,\n height: obj.height,\n };\n return config;\n}\n","import { AssetHandle } from \"@yagejs/core\";\nimport type { TiledMapData } from \"./tiled/types.js\";\n\n/** Create a typed asset handle for a Tiled map JSON. */\nexport function tiledMap(path: string): AssetHandle<TiledMapData> {\n return new AssetHandle(\"tiledMap\", path);\n}\n","import type { ColliderConfig as PhysicsColliderConfig } from \"@yagejs/physics\";\nimport type { TilemapColliderConfig } from \"./types.js\";\n\n/**\n * Convert tilemap TilemapColliderConfig[] (top-left origin rects/polygons) into\n * physics-package ColliderConfig[] (center-origin shape + offset).\n */\nexport function toPhysicsColliders(\n shapes: TilemapColliderConfig[],\n): PhysicsColliderConfig[] {\n return shapes.map(toPhysicsCollider);\n}\n\nfunction toPhysicsCollider(config: TilemapColliderConfig): PhysicsColliderConfig {\n switch (config.type) {\n case \"polygon\":\n return {\n shape: {\n type: \"polygon\",\n vertices: config.vertices,\n },\n offset: { x: config.x, y: config.y },\n };\n case \"rect\":\n return {\n shape: { type: \"box\", width: config.width, height: config.height },\n offset: {\n x: config.x + config.width / 2,\n y: config.y + config.height / 2,\n },\n };\n }\n}\n","import type { HasProperties, MapObject } from \"./types.js\";\n\n/**\n * Get a single property value by name.\n * Returns `undefined` if the property is not found.\n */\nexport function getProperty<T = unknown>(\n obj: HasProperties,\n name: string,\n): T | undefined {\n const prop = obj.properties?.find((p) => p.name === name);\n return prop?.value as T | undefined;\n}\n\n/**\n * Get a pseudo-array of property values.\n *\n * Tiled doesn't support array properties natively, so a common convention\n * is to use indexed names like `spawns[0]`, `spawns[1]`, etc.\n * This function collects them into a proper array, preserving index order.\n */\nexport function getPropertyArray<T = unknown>(\n obj: HasProperties,\n name: string,\n): T[] {\n const pattern = new RegExp(`^${escapeRegex(name)}\\\\[(\\\\d+)\\\\]$`);\n const values: T[] = [];\n\n if (!obj.properties) return values;\n\n for (const prop of obj.properties) {\n const match = prop.name.match(pattern);\n if (match) {\n const index = Number.parseInt(match[1]!, 10);\n values[index] = prop.value as T;\n }\n }\n\n return values;\n}\n\n/**\n * Resolve a property of `type: \"object\"` (an ID reference) to the actual MapObject.\n * Returns `undefined` if the property doesn't exist or the referenced object isn't found.\n */\nexport function resolveObjectRef(\n obj: HasProperties,\n propName: string,\n allObjects: MapObject[],\n): MapObject | undefined {\n const id = getProperty<number>(obj, propName);\n if (id === undefined) return undefined;\n return allObjects.find((o) => o.id === id);\n}\n\n/**\n * Resolve a pseudo-array of object ID references to actual MapObjects.\n * Uses the `name[0]`, `name[1]` convention.\n */\nexport function resolveObjectRefArray(\n obj: HasProperties,\n propName: string,\n allObjects: MapObject[],\n): MapObject[] {\n const ids = getPropertyArray<number>(obj, propName);\n return ids\n .map((id) => allObjects.find((o) => o.id === id))\n .filter((o): o is MapObject => o !== undefined);\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,eAAgC;AAEhC,IAAAC,eAAmC;;;ACFnC,kBAOO;AAgBP,IAAM,uBAAmD;AAAA,EACvD,IAAI;AAAA,EAEJ,WAAW;AAAA,IACT,MAAM,0BAAc;AAAA,IACpB,UAAU,iCAAqB;AAAA,EACjC;AAAA,EAEA,MAAM,UACJ,OACA,eACkB;AAClB,QAAI,CAAC,eAAe,IAAK,QAAO;AAChC,QAAI,iBAAK,QAAQ,cAAc,GAAG,EAAE,YAAY,MAAM,QAAS,QAAO;AACtE,UAAM,MAAM;AACZ,WAAO,CAAC,EAAE,IAAI,YAAY,IAAI;AAAA,EAChC;AAAA,EAEA,MAAM,MACJ,OACA,eACA,QACuB;AACvB,UAAM,MAAM,eAAe;AAC3B,QAAI,CAAC,OAAO,CAAC,OAAQ,QAAO;AAE5B,QAAI,WAAW,iBAAK,QAAQ,GAAG;AAC/B,QAAI,YAAY,CAAC,SAAS,SAAS,GAAG,GAAG;AACvC,kBAAY;AAAA,IACd;AAEA,eAAW,cAAc,MAAM,UAA0B;AACvD,UAAI,WAAW,QAAQ;AAErB,cAAM,cAAc,WAAW,WAAW;AAC1C,cAAM,cAAe,MAAM,OAAO,KAAkB;AAAA,UAClD,KAAK;AAAA,QACP,CAAC;AACD,mBAAW,OAAO;AAAA,MACpB;AAEA,YAAM,UAAU,WAAW;AAC3B,UAAI,CAAC,QAAS;AAGd,UAAI,QAAQ,SAAS,CAAC,QAAQ,OAAO,QAAQ;AAC3C,cAAM,YAAY,WAAW,QAAQ;AACrC,cAAM,cAAc,MAAM,mBAAO,KAAc,SAAS;AACxD,cAAM,OAAO,QAAQ;AACrB,cAAM,KAAK,QAAQ;AACnB,cAAM,KAAK,QAAQ;AACnB,cAAM,SAAS,QAAQ,UAAU;AACjC,cAAM,UAAU,QAAQ,WAAW;AAEnC,iBAAS,KAAK,GAAG,KAAK,QAAQ,WAAW,MAAM;AAC7C,gBAAM,MAAM,KAAK;AACjB,gBAAM,MAAM,KAAK,MAAM,KAAK,IAAI;AAChC,gBAAM,IAAI,SAAS,OAAO,KAAK;AAC/B,gBAAM,IAAI,SAAS,OAAO,KAAK;AAE/B,gBAAM,QAAQ,IAAI,sBAAU,GAAG,GAAG,IAAI,EAAE;AACxC,gBAAM,SAAS,IAAI,oBAAQ;AAAA,YACzB,QAAQ,YAAY;AAAA,YACpB;AAAA,UACF,CAAC;AAGD,gBAAM,WAAW,GAAG,QAAQ,IAAI,IAAI,EAAE;AACtC,6BAAO,MAAM,IAAI,UAAU,MAAM;AAAA,QACnC;AAAA,MACF;AAAA,IAGF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,SAAS;AAAA,EAAC;AACZ;AAGO,IAAM,yBAAyB;AAAA,EACpC,WAAW,0BAAc;AAAA,EACzB,QAAQ;AACV;;;AC5GA,IAAAC,eAAwD;;;ACAxD,kBAAmD;AACnD,IAAAC,eAAkC;AAClC,sBAAmC;;;ACFnC,qBAAiC;AACjC,IAAAC,eAA2C;AAoBpC,SAAS,cAAc,KAAgC;AAC5D,QAAM,aAA8B,CAAC;AACrC,QAAM,eAAkC,CAAC;AAEzC,aAAW,SAAS,IAAI,QAAQ;AAC9B,QAAI,MAAM,SAAS,aAAa;AAC9B,iBAAW,KAAK;AAAA,QACd,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM;AAAA,QACb,QAAQ,MAAM;AAAA,QACd,SAAS,MAAM;AAAA,MACjB,CAAC;AAAA,IACH,WAAW,MAAM,SAAS,eAAe;AACvC,mBAAa,KAAK;AAAA,QAChB,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM,QAAQ,IAAI,sBAAsB;AAAA,QACjD,SAAS,MAAM;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ,WAAW,IAAI;AAAA,IACf,YAAY,IAAI;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AA9BgB;AAgChB,SAAS,uBAAuB,KAA4B;AAC1D,QAAM,SAAoB;AAAA,IACxB,IAAI,IAAI;AAAA,IACR,MAAM,IAAI;AAAA,IACV,GAAG,IAAI;AAAA,IACP,GAAG,IAAI;AAAA,IACP,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,SAAS,IAAI;AAAA,EACf;AAEA,QAAM,MAAM,IAAI,SAAS,IAAI;AAC7B,MAAI,IAAK,QAAO,QAAQ;AACxB,MAAI,IAAI,UAAU,KAAM,QAAO,QAAQ;AACvC,MAAI,IAAI,QAAS,QAAO,UAAU,IAAI;AACtC,MAAI,IAAI,YAAY;AAClB,WAAO,aAAa,IAAI,WAAW,IAAI,CAAC,OAAO;AAAA,MAC7C,MAAM,EAAE;AAAA,MACR,MAAM,EAAE;AAAA,MACR,OAAO,EAAE;AAAA,IACX,EAAE;AAAA,EACJ;AAEA,SAAO;AACT;AAzBS;AAiCT,SAAS,YAAY,UAAwB,KAAgC;AAC3E,MAAI,SAA4B;AAChC,aAAW,MAAM,UAAU;AACzB,QAAI,GAAG,YAAY,KAAK;AACtB,UAAI,CAAC,UAAU,GAAG,WAAW,OAAO,UAAU;AAC5C,iBAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAVS;AAeT,SAAS,mBACP,KACA,SACgB;AAChB,QAAM,OAAO,QAAQ;AACrB,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAU,MAAM,QAAQ;AAE9B,MAAI,KAAK,OAAO,QAAQ;AAEtB,UAAM,WAAW,KAAK,MAAM,OAAO;AACnC,QAAI,CAAC,UAAU,MAAO,QAAO;AAC7B,UAAM,gBAAgB,SAAS,MAAM,MAAM,QAAQ;AACnD,UAAM,WAAW,gBAAgB,CAAC;AAClC,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,MAAM,oBAAO,IAAa,QAAQ;AACxC,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,KAAK,OAAO;AAEd,UAAM,WAAW,GAAG,KAAK,IAAI,IAAI,OAAO;AACxC,UAAM,MAAM,oBAAO,IAAa,QAAQ;AACxC,QAAI,IAAK,QAAO;AAGhB,UAAM,gBAAgB,KAAK,MAAM,MAAM,QAAQ;AAC/C,UAAM,WAAW,gBAAgB,CAAC;AAClC,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,UAAU,oBAAO,IAAa,QAAQ;AAC5C,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,OAAO,KAAK;AAClB,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,KAAK;AAChB,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,UAAU,KAAK,WAAW;AAChC,UAAM,MAAM,UAAU;AACtB,UAAM,MAAM,KAAK,MAAM,UAAU,IAAI;AACrC,UAAM,IAAI,SAAS,OAAO,KAAK;AAC/B,UAAM,IAAI,SAAS,OAAO,KAAK;AAE/B,WAAO,IAAI,qBAAQ;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,OAAO,IAAI,uBAAU,GAAG,GAAG,IAAI,EAAE;AAAA,IACnC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAjDS;AA0DF,SAAS,oBACd,KACA,YACoB;AACpB,QAAM,aAAa,IAAI,OAAO;AAAA,IAC5B,CAAC,MAAsB,EAAE,SAAS;AAAA,EACpC;AAEA,QAAM,WAAW,aACb,WAAW,OAAO,CAAC,MAAM,WAAW,SAAS,EAAE,IAAI,CAAC,IACpD;AAEJ,SAAO,SAAS,IAAI,CAAC,UAAU;AAC7B,UAAM,UAAU,IAAI,gCAAiB;AACrC,UAAM,EAAE,MAAM,MAAM,IAAI;AAExB,aAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAChD,YAAM,MAAM,KAAK,KAAK;AACtB,UAAI,QAAQ,EAAG;AAEf,YAAM,UAAU,YAAY,IAAI,UAAU,GAAG;AAC7C,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,MAAM,iCAAiC,GAAG,EAAE;AAAA,MACxD;AAEA,YAAM,UAAU,mBAAmB,KAAK,OAAO;AAC/C,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI;AAAA,UACR,0CAA0C,GAAG,gBAAgB,QAAQ,MAAM,IAAI;AAAA,QACjF;AAAA,MACF;AAEA,YAAM,IAAI,QAAQ;AAClB,YAAM,IAAI,KAAK,MAAM,QAAQ,KAAK;AAClC,cAAQ,KAAK,SAAS,IAAI,IAAI,WAAW,IAAI,IAAI,UAAU;AAAA,IAC7D;AAEA,WAAO;AAAA,EACT,CAAC;AACH;AAvCgB;AAgDT,SAAS,eACd,KACA,iBAC8B;AAC9B,QAAM,eAAe,IAAI,OAAO;AAAA,IAC9B,CAAC,MAAwB,EAAE,SAAS;AAAA,EACtC;AAEA,QAAM,WAAW,kBACb,aAAa,OAAO,CAAC,MAAM,EAAE,SAAS,eAAe,IACrD;AAEJ,QAAM,SAAuC,CAAC;AAE9C,aAAW,SAAS,UAAU;AAC5B,eAAW,OAAO,MAAM,SAAS;AAC/B,YAAM,MAAM,IAAI,SAAS,IAAI,QAAQ,IAAI;AACzC,UAAI,CAAC,OAAO,GAAG,GAAG;AAChB,eAAO,GAAG,IAAI,CAAC;AAAA,MACjB;AACA,aAAO,GAAG,EAAE,KAAK,GAAG;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AACT;AAzBgB;;;AC7LT,SAAS,uBACd,KACA,iBACyB;AACzB,QAAM,WAAW,kBACb,IAAI,aAAa,OAAO,CAAC,MAAM,EAAE,SAAS,eAAe,IACzD,IAAI;AAER,QAAM,SAAkC,CAAC;AAEzC,aAAW,SAAS,UAAU;AAC5B,eAAW,OAAO,MAAM,SAAS;AAC/B,YAAM,QAAQ,uBAAuB,GAAG;AACxC,UAAI,MAAO,QAAO,KAAK,KAAK;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO;AACT;AAlBgB;AAwBhB,SAAS,uBAAuB,KAA8C;AAE5E,MAAI,IAAI,MAAO,QAAO;AAEtB,MAAI,IAAI,SAAS;AACf,UAAMC,UAAgC;AAAA,MACpC,MAAM;AAAA,MACN,GAAG,IAAI;AAAA,MACP,GAAG,IAAI;AAAA,MACP,UAAU,IAAI,QAAQ,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE;AAAA,IACvD;AACA,WAAOA;AAAA,EACT;AAGA,QAAM,SAA6B;AAAA,IACjC,MAAM;AAAA,IACN,GAAG,IAAI;AAAA,IACP,GAAG,IAAI;AAAA,IACP,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,EACd;AACA,SAAO;AACT;AAvBS;;;AF1CT;AAgCA,gCAAC;AACM,IAAM,oBAAN,MAAM,2BAAyB,4BAAU;AAAA,EAjChD,OAiCgD;AAAA;AAAA;AAAA,EACrC;AAAA,EACA;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAAkC;AAC5C,UAAM;AAEN,QAAI,CAAC,QAAQ,OAAO,CAAC,QAAQ,QAAQ;AACnC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,SAAK,UAAU,QAAQ,UAAU;AACjC,UAAMC,YAAW,QAAQ,OAAO,oBAAO,IAAkB,QAAQ,MAAO;AACxE,QAAI,CAACA,WAAU;AACb,YAAM,IAAI;AAAA,QACR,0BAA0B,QAAQ,MAAM;AAAA,MAC1C;AAAA,IACF;AAEA,SAAK,YAAYA;AACjB,SAAK,OAAO,cAAcA,SAAQ;AAClC,SAAK,aAAa,QAAQ;AAC1B,SAAK,kBAAkB,QAAQ,SAAS;AACxC,SAAK,YAAY,IAAI,uBAAU;AAAA,EACjC;AAAA,EAEA,QAAc;AACZ,UAAM,gBAAgB,oBAAoB,KAAK,WAAW,KAAK,UAAU;AACzE,eAAW,SAAS,eAAe;AACjC,WAAK,UAAU,SAAS,KAAK;AAAA,IAC/B;AAEA,UAAM,cAAc,KAAK,IAAI,kCAAkB,EAAE,IAAI,KAAK,eAAe;AACzE,gBAAY,UAAU,SAAS,KAAK,SAAS;AAAA,EAC/C;AAAA,EAEA,YAAkB;AAChB,SAAK,UAAU,iBAAiB;AAChC,SAAK,UAAU,QAAQ,EAAE,UAAU,KAAK,CAAC;AAAA,EAC3C;AAAA,EAEA,YAAyC;AACvC,QAAI,CAAC,KAAK,SAAS;AACjB,cAAQ;AAAA,QACN,wBAAwB,KAAK,QAAQ,IAAI;AAAA,MAE3C;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,GAAI,KAAK,cAAc,EAAE,QAAQ,KAAK,WAAW;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,MAA8C;AAChE,WAAO,IAAI,kBAAiB;AAAA,MAC1B,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,GAAI,KAAK,UAAU,EAAE,QAAQ,KAAK,OAAO;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,IAAI,UAAkB;AACpB,WAAO,KAAK,KAAK,QAAQ,KAAK,KAAK;AAAA,EACrC;AAAA;AAAA,EAGA,IAAI,WAAmB;AACrB,WAAO,KAAK,KAAK,SAAS,KAAK,KAAK;AAAA,EACtC;AAAA;AAAA,EAGA,IAAI,YAAoB;AACtB,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA;AAAA,EAGA,IAAI,aAAqB;AACvB,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UACE,QACA,QACA,WACe;AACf,UAAM,YAAY,KAAK,OAAO,OAAO,qBAAS;AAC9C,UAAM,UAAU,YAAY,UAAU,SAAS,IAAI;AACnD,UAAM,UAAU,YAAY,UAAU,SAAS,IAAI;AACnD,UAAM,SAAS,SAAS;AACxB,UAAM,SAAS,SAAS;AAExB,UAAM,MAAM,KAAK,MAAM,SAAS,KAAK,KAAK,SAAS;AACnD,UAAM,MAAM,KAAK,MAAM,SAAS,KAAK,KAAK,UAAU;AAEpD,QAAI,MAAM,KAAK,OAAO,KAAK,KAAK,MAAO,QAAO;AAC9C,QAAI,MAAM,KAAK,OAAO,KAAK,KAAK,OAAQ,QAAO;AAE/C,UAAM,SAAS,YACX,KAAK,KAAK,WAAW,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS,IACvD,KAAK,KAAK;AAGd,aAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,YAAM,QAAQ,OAAO,CAAC;AACtB,YAAM,MAAM,MAAM,KAAK,MAAM,MAAM,QAAQ,GAAG;AAC9C,UAAI,QAAQ,UAAa,QAAQ,EAAG,QAAO;AAAA,IAC7C;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,mBAAmB,iBAAmD;AACpE,WAAO,uBAAuB,KAAK,MAAM,eAAe;AAAA,EAC1D;AAAA;AAAA,EAGA,WAAW,iBAAuD;AAChE,UAAM,WAAW,kBACb,KAAK,KAAK,aAAa,OAAO,CAAC,MAAM,EAAE,SAAS,eAAe,IAC/D,KAAK,KAAK;AAEd,UAAM,SAAsC,CAAC;AAE7C,eAAW,SAAS,UAAU;AAC5B,iBAAW,OAAO,MAAM,SAAS;AAC/B,cAAM,MAAM,IAAI,SAAS,IAAI;AAC7B,YAAI,CAAC,OAAO,GAAG,GAAG;AAChB,iBAAO,GAAG,IAAI,CAAC;AAAA,QACjB;AACA,eAAO,GAAG,EAAE,KAAK,GAAG;AAAA,MACtB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AAtJO;AAAM,oBAAN,gDADP,8BACa;AAAN,4BAAM;AAAN,IAAM,mBAAN;;;AD5BA,IAAM,sBAAN,cAAkC,oBAAO;AAAA,EALhD,OAKgD;AAAA;AAAA;AAAA,EACrC,QAAQ,mBAAM;AAAA,EACd,WAAW;AAAA;AAAA,EAEZ;AAAA,EAER,WAAW,SAA8B;AACvC,UAAM,aAAa,QAAQ,QAAQ,0BAAa;AAChD,SAAK,QAAQ,WAAW,SAAS,CAAC,wBAAW,gBAAgB,CAAC;AAAA,EAChE;AAAA,EAEA,SAAe;AACb,eAAW,UAAU,KAAK,OAAO;AAC/B,YAAM,YAAY,OAAO,IAAI,sBAAS;AACtC,YAAM,UAAU,OAAO,IAAI,gBAAgB;AAC3C,UAAI,CAAC,QAAQ,QAAS;AAEtB,cAAQ,UAAU,SAAS,IAAI,UAAU,cAAc;AACvD,cAAQ,UAAU,SAAS,IAAI,UAAU,cAAc;AACvD,cAAQ,UAAU,WAAW,UAAU;AACvC,cAAQ,UAAU,MAAM,IAAI,UAAU,WAAW;AACjD,cAAQ,UAAU,MAAM,IAAI,UAAU,WAAW;AAAA,IACnD;AAAA,EACF;AACF;;;AFrBO,IAAM,gBAAN,MAAsC;AAAA,EAR7C,OAQ6C;AAAA;AAAA;AAAA,EAClC,OAAO;AAAA,EACP,UAAU;AAAA,EACV,eAAe,CAAC,UAAU;AAAA,EAEnC,QAAQ,SAA8B;AAEpC,4BAAW,IAAI,sBAAsB;AAGrC,UAAM,KAAK,QAAQ,WAAW,4BAAe;AAC7C,QAAI,eAAe,YAAY;AAAA,MAC7B,MAAM,wBAACC,UAAiB,oBAAO,KAAmBA,KAAI,GAAhD;AAAA,MACN,QAAQ,wBAACA,UAAiB;AACxB,4BAAO,OAAOA,KAAI;AAAA,MACpB,GAFQ;AAAA,IAGV,CAAC;AAAA,EACH;AAAA,EAEA,gBAAgB,WAAkC;AAChD,cAAU,IAAI,IAAI,oBAAoB,CAAC;AAAA,EACzC;AACF;;;AM9BA,IAAAC,eAA4B;AAIrB,SAAS,SAASC,OAAyC;AAChE,SAAO,IAAI,yBAAY,YAAYA,KAAI;AACzC;AAFgB;;;ACGT,SAAS,mBACd,QACyB;AACzB,SAAO,OAAO,IAAI,iBAAiB;AACrC;AAJgB;AAMhB,SAAS,kBAAkB,QAAsD;AAC/E,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO;AAAA,QACL,OAAO;AAAA,UACL,MAAM;AAAA,UACN,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,QAAQ,EAAE,GAAG,OAAO,GAAG,GAAG,OAAO,EAAE;AAAA,MACrC;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,OAAO,EAAE,MAAM,OAAO,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;AAAA,QACjE,QAAQ;AAAA,UACN,GAAG,OAAO,IAAI,OAAO,QAAQ;AAAA,UAC7B,GAAG,OAAO,IAAI,OAAO,SAAS;AAAA,QAChC;AAAA,MACF;AAAA,EACJ;AACF;AAnBS;;;ACPF,SAAS,YACd,KACA,MACe;AACf,QAAM,OAAO,IAAI,YAAY,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AACxD,SAAO,MAAM;AACf;AANgB;AAeT,SAAS,iBACd,KACA,MACK;AACL,QAAM,UAAU,IAAI,OAAO,IAAI,YAAY,IAAI,CAAC,eAAe;AAC/D,QAAM,SAAc,CAAC;AAErB,MAAI,CAAC,IAAI,WAAY,QAAO;AAE5B,aAAW,QAAQ,IAAI,YAAY;AACjC,UAAM,QAAQ,KAAK,KAAK,MAAM,OAAO;AACrC,QAAI,OAAO;AACT,YAAM,QAAQ,OAAO,SAAS,MAAM,CAAC,GAAI,EAAE;AAC3C,aAAO,KAAK,IAAI,KAAK;AAAA,IACvB;AAAA,EACF;AAEA,SAAO;AACT;AAlBgB;AAwBT,SAAS,iBACd,KACA,UACA,YACuB;AACvB,QAAM,KAAK,YAAoB,KAAK,QAAQ;AAC5C,MAAI,OAAO,OAAW,QAAO;AAC7B,SAAO,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3C;AARgB;AAcT,SAAS,sBACd,KACA,UACA,YACa;AACb,QAAM,MAAM,iBAAyB,KAAK,QAAQ;AAClD,SAAO,IACJ,IAAI,CAAC,OAAO,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAC/C,OAAO,CAAC,MAAsB,MAAM,MAAS;AAClD;AATgB;AAWhB,SAAS,YAAY,KAAqB;AACxC,SAAO,IAAI,QAAQ,uBAAuB,MAAM;AAClD;AAFS;","names":["import_core","import_pixi","import_core","import_pixi","import_pixi","config","tiledMap","path","import_core","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/TilemapPlugin.ts","../src/tiled/tiledMapLoader.ts","../src/TilemapRenderSystem.ts","../src/TilemapComponent.ts","../src/tiled/parseTiledMap.ts","../src/colliders.ts","../src/keys.ts","../src/properties.ts","../src/assets.ts","../src/toPhysicsColliders.ts"],"sourcesContent":["// Plugin\nexport { TilemapPlugin } from \"./TilemapPlugin.js\";\n\n// Component\nexport { TilemapComponent } from \"./TilemapComponent.js\";\nexport type {\n TilemapComponentOptions,\n TilemapComponentData,\n} from \"./TilemapComponent.js\";\n\n// System\nexport { TilemapRenderSystem } from \"./TilemapRenderSystem.js\";\n\n// Asset handle factory\nexport { tiledMap } from \"./assets.js\";\n\n// Stable identity helpers\nexport { tiledObjectKey } from \"./keys.js\";\n\n// Collision extraction\nexport { extractCollisionShapes } from \"./colliders.js\";\nexport { toPhysicsColliders } from \"./toPhysicsColliders.js\";\n\n// Property utilities\nexport {\n getProperty,\n getPropertyArray,\n resolveObjectRef,\n resolveObjectRefArray,\n} from \"./properties.js\";\n\n// Generic types\nexport type {\n TilemapData,\n TileLayerData,\n ObjectLayerData,\n MapObject,\n MapObjectProperty,\n HasProperties,\n TilemapColliderConfig,\n RectColliderConfig,\n PolygonColliderConfig,\n} from \"./types.js\";\n\n// Tiled-specific (re-exported for backward compatibility)\nexport { tiledMapAssetExtension } from \"./tiled/tiledMapLoader.js\";\nexport {\n createTilemapLayers,\n extractObjects,\n toTilemapData,\n} from \"./tiled/parseTiledMap.js\";\nexport type {\n TiledMapData,\n TileLayer,\n ObjectGroup,\n TileObject,\n RectangleObject,\n PolygonObject,\n PointObject,\n TileObjectProperty,\n TilesetRef,\n TilesetData,\n TileData,\n} from \"./tiled/types.js\";\n","import { AssetManagerKey } from \"@yagejs/core\";\nimport type { EngineContext, Plugin, SystemScheduler } from \"@yagejs/core\";\nimport { extensions, Assets } from \"pixi.js\";\nimport { tiledMapAssetExtension } from \"./tiled/tiledMapLoader.js\";\nimport { TilemapRenderSystem } from \"./TilemapRenderSystem.js\";\nimport type { TiledMapData } from \"./tiled/types.js\";\n\n/** Plugin that adds Tiled map loading and rendering to YAGE. */\nexport class TilemapPlugin implements Plugin {\n readonly name = \"tilemap\";\n readonly version = \"2.0.0\";\n readonly dependencies = [\"renderer\"] as const;\n\n install(context: EngineContext): void {\n // Register PixiJS loader extension for Tiled map JSON files\n extensions.add(tiledMapAssetExtension);\n\n // Register \"tiledMap\" loader with AssetManager\n const am = context.tryResolve(AssetManagerKey);\n am?.registerLoader(\"tiledMap\", {\n load: (path: string) => Assets.load<TiledMapData>(path),\n unload: (path: string) => {\n Assets.unload(path);\n },\n });\n }\n\n registerSystems(scheduler: SystemScheduler): void {\n scheduler.add(new TilemapRenderSystem());\n }\n}\n","import {\n ExtensionType,\n LoaderParserPriority,\n Assets,\n path,\n Texture,\n Rectangle,\n} from \"pixi.js\";\nimport type { LoaderParser, ResolvedAsset, Loader } from \"pixi.js\";\nimport type { TiledMapData, TilesetData, TilesetRef } from \"./types.js\";\n\n/**\n * PixiJS loader extension that detects Tiled map JSON files and resolves\n * their tileset references.\n *\n * Supports two tileset formats:\n * 1. **Collection-of-images** — tileset has `tiles[]` with image paths.\n * Assumes textures are already in the PixiJS cache (e.g. from a\n * pre-loaded spritesheet atlas).\n * 2. **Single-image tileset** — tileset has an `image` property pointing\n * to a spritesheet. The loader loads the image and creates sub-textures\n * for each tile based on grid layout.\n */\nconst tiledMapLoaderParser: LoaderParser<TiledMapData> = {\n id: \"tiledMapLoader\",\n\n extension: {\n type: ExtensionType.LoadParser,\n priority: LoaderParserPriority.High,\n },\n\n async testParse(\n asset: TiledMapData,\n resolvedAsset?: ResolvedAsset,\n ): Promise<boolean> {\n if (!resolvedAsset?.src) return false;\n if (path.extname(resolvedAsset.src).toLowerCase() !== \".json\") return false;\n const obj = asset as unknown as Record<string, unknown>;\n return !!(obj.tilesets && obj.layers);\n },\n\n async parse(\n asset: TiledMapData,\n resolvedAsset?: ResolvedAsset,\n loader?: Loader,\n ): Promise<TiledMapData> {\n const src = resolvedAsset?.src;\n if (!src || !loader) return asset;\n\n let basePath = path.dirname(src);\n if (basePath && !basePath.endsWith(\"/\")) {\n basePath += \"/\";\n }\n\n for (const tilesetRef of asset.tilesets as TilesetRef[]) {\n if (tilesetRef.source) {\n // External tileset JSON — load it\n const tilesetPath = basePath + tilesetRef.source;\n const tilesetData = (await loader.load<TilesetData>({\n src: tilesetPath,\n })) as TilesetData;\n tilesetRef.data = tilesetData;\n }\n\n const tileset = tilesetRef.data;\n if (!tileset) continue;\n\n // Single-image tileset: load the image and create sub-textures\n if (tileset.image && !tileset.tiles?.length) {\n const imagePath = basePath + tileset.image;\n const baseTexture = await Assets.load<Texture>(imagePath);\n const cols = tileset.columns;\n const tw = tileset.tilewidth;\n const th = tileset.tileheight;\n const margin = tileset.margin ?? 0;\n const spacing = tileset.spacing ?? 0;\n\n for (let id = 0; id < tileset.tilecount; id++) {\n const col = id % cols;\n const row = Math.floor(id / cols);\n const x = margin + col * (tw + spacing);\n const y = margin + row * (th + spacing);\n\n const frame = new Rectangle(x, y, tw, th);\n const subtex = new Texture({\n source: baseTexture.source,\n frame,\n });\n\n // Store subtexture in PixiJS cache with a key like \"tileset-name:id\"\n const cacheKey = `${tileset.name}:${id}`;\n Assets.cache.set(cacheKey, subtex);\n }\n }\n // Collection-of-images: textures are expected to already be\n // in the PixiJS cache (loaded via spritesheet atlas).\n }\n\n return asset;\n },\n\n unload() {},\n};\n\n/** PixiJS asset extension bundle for Tiled map JSON files. */\nexport const tiledMapAssetExtension = {\n extension: ExtensionType.Asset,\n loader: tiledMapLoaderParser,\n};\n","import { System, Phase, Transform, QueryCacheKey } from \"@yagejs/core\";\nimport type { EngineContext, QueryResult } from \"@yagejs/core\";\nimport { TilemapComponent } from \"./TilemapComponent.js\";\n\n/** Syncs Transform to TilemapComponent display containers. */\nexport class TilemapRenderSystem extends System {\n readonly phase = Phase.Render;\n readonly priority = -1; // Before DisplaySystem (0), so tilemaps render behind sprites\n\n private query!: QueryResult;\n\n onRegister(context: EngineContext): void {\n const queryCache = context.resolve(QueryCacheKey);\n this.query = queryCache.register([Transform, TilemapComponent]);\n }\n\n update(): void {\n for (const entity of this.query) {\n const transform = entity.get(Transform);\n const tilemap = entity.get(TilemapComponent);\n if (!tilemap.enabled) continue;\n\n tilemap.container.position.x = transform.worldPosition.x;\n tilemap.container.position.y = transform.worldPosition.y;\n tilemap.container.rotation = transform.worldRotation;\n tilemap.container.scale.x = transform.worldScale.x;\n tilemap.container.scale.y = transform.worldScale.y;\n }\n }\n}\n","import { Component, Transform, serializable } from \"@yagejs/core\";\nimport type { AssetHandle } from \"@yagejs/core\";\nimport { Assets, Container } from \"pixi.js\";\nimport { SceneRenderTreeKey } from \"@yagejs/renderer\";\nimport { createTilemapLayers, toTilemapData } from \"./tiled/parseTiledMap.js\";\nimport { extractCollisionShapes } from \"./colliders.js\";\nimport { tiledObjectKey } from \"./keys.js\";\nimport {\n getProperty,\n getPropertyArray,\n resolveObjectRef,\n resolveObjectRefArray,\n} from \"./properties.js\";\nimport type { TiledMapData } from \"./tiled/types.js\";\nimport type {\n TilemapData,\n MapObject,\n TilemapColliderConfig,\n} from \"./types.js\";\n\n/** Options for creating a TilemapComponent. */\nexport interface TilemapComponentOptions {\n /** Asset handle for the map. Preferred — captures both the parsed data and the asset path. */\n source?: AssetHandle<TiledMapData>;\n /** Parsed Tiled map data. Use only when you don't have an AssetHandle. Save/load and auto-keys require `mapKey` or `source`. */\n map?: TiledMapData;\n /** Asset path to the Tiled JSON. Resolved via `Assets.get`. Save/load uses this. */\n mapKey?: string;\n /** Which tile layers to render. Omit to render all. */\n layers?: string[];\n /** Render layer name. Default: \"default\". */\n layer?: string;\n /**\n * Override prefix used when auto-keying entities spawned from Tiled objects.\n * Defaults to `mapKey`. Set this when multiple instances of the same map need\n * distinct entity-key namespaces (e.g. instanced dungeons).\n */\n keyPrefix?: string;\n}\n\n/** Serializable snapshot of a TilemapComponent. */\nexport interface TilemapComponentData {\n mapKey: string;\n layers?: string[];\n layer: string;\n keyPrefix?: string;\n}\n\n/** Component that renders a Tiled map using @pixi/tilemap. */\n@serializable\nexport class TilemapComponent extends Component {\n readonly container: Container;\n readonly data: TilemapData;\n /** Asset path of this map, or `null` if constructed from a raw `TiledMapData` without one. */\n readonly mapKey: string | null;\n /** Prefix used to derive auto-keys for entities spawned from objects. */\n readonly keyPrefix: string | null;\n private readonly _tiledMap: TiledMapData;\n private readonly layerNames: string[] | undefined;\n private readonly renderLayerName: string;\n private readonly _explicitKeyPrefix: string | undefined;\n /** Lazy flat-list cache. The parsed map is treated as immutable post-construction; if that ever changes, callers must invalidate. */\n private _allObjectsCache: MapObject[] | undefined;\n\n constructor(options: TilemapComponentOptions) {\n super();\n\n const sourceCount =\n (options.source ? 1 : 0) +\n (options.map ? 1 : 0) +\n (options.mapKey ? 1 : 0);\n if (sourceCount === 0) {\n throw new Error(\n \"TilemapComponent requires one of `source`, `map`, or `mapKey`.\",\n );\n }\n\n if (options.source) {\n this.mapKey = options.source.path;\n const data = Assets.get<TiledMapData>(options.source.path);\n if (!data) {\n throw new Error(\n `TilemapComponent: source \"${options.source.path}\" is not loaded. Add it to scene preload.`,\n );\n }\n this._tiledMap = data;\n } else if (options.mapKey) {\n this.mapKey = options.mapKey;\n const data = Assets.get<TiledMapData>(options.mapKey);\n if (!data) {\n throw new Error(\n `TilemapComponent: map \"${options.mapKey}\" is not loaded. Add it to scene preload.`,\n );\n }\n this._tiledMap = data;\n } else {\n this.mapKey = null;\n this._tiledMap = options.map!;\n }\n\n this.data = toTilemapData(this._tiledMap);\n this.layerNames = options.layers;\n this.renderLayerName = options.layer ?? \"default\";\n this._explicitKeyPrefix = options.keyPrefix;\n this.keyPrefix = options.keyPrefix ?? this.mapKey;\n this.container = new Container();\n }\n\n onAdd(): void {\n const tilemapLayers = createTilemapLayers(this._tiledMap, this.layerNames);\n for (const layer of tilemapLayers) {\n this.container.addChild(layer);\n }\n\n const renderLayer = this.use(SceneRenderTreeKey).get(this.renderLayerName);\n renderLayer.container.addChild(this.container);\n }\n\n onDestroy(): void {\n this.container.removeFromParent();\n this.container.destroy({ children: true });\n }\n\n serialize(): TilemapComponentData | null {\n if (!this.mapKey) {\n console.warn(\n `TilemapComponent on \"${this.entity?.name}\": created with a TiledMapData object. ` +\n `Use { source } or { mapKey } for save/load support.`,\n );\n return null;\n }\n return {\n mapKey: this.mapKey,\n layer: this.renderLayerName,\n ...(this.layerNames && { layers: this.layerNames }),\n ...(this._explicitKeyPrefix !== undefined && {\n keyPrefix: this._explicitKeyPrefix,\n }),\n };\n }\n\n static fromSnapshot(data: TilemapComponentData): TilemapComponent {\n return new TilemapComponent({\n mapKey: data.mapKey,\n layer: data.layer,\n ...(data.layers && { layers: data.layers }),\n ...(data.keyPrefix !== undefined && { keyPrefix: data.keyPrefix }),\n });\n }\n\n /** Map width in pixels. */\n get widthPx(): number {\n return this.data.width * this.data.tileWidth;\n }\n\n /** Map height in pixels. */\n get heightPx(): number {\n return this.data.height * this.data.tileHeight;\n }\n\n /** Tile width in pixels. */\n get tileWidth(): number {\n return this.data.tileWidth;\n }\n\n /** Tile height in pixels. */\n get tileHeight(): number {\n return this.data.tileHeight;\n }\n\n /**\n * Returns the tile GID at a world position, accounting for entity Transform offset.\n * Returns null if the position is outside the map or the tile is empty.\n */\n getTileAt(\n worldX: number,\n worldY: number,\n layerName?: string,\n ): number | null {\n const transform = this.entity.tryGet(Transform);\n const offsetX = transform ? transform.position.x : 0;\n const offsetY = transform ? transform.position.y : 0;\n const localX = worldX - offsetX;\n const localY = worldY - offsetY;\n\n const col = Math.floor(localX / this.data.tileWidth);\n const row = Math.floor(localY / this.data.tileHeight);\n\n if (col < 0 || col >= this.data.width) return null;\n if (row < 0 || row >= this.data.height) return null;\n\n const layers = layerName\n ? this.data.tileLayers.filter((l) => l.name === layerName)\n : this.data.tileLayers;\n\n // Return first non-zero GID found (from last layer to first for top-most)\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i]!;\n const gid = layer.data[row * layer.width + col];\n if (gid !== undefined && gid !== 0) return gid;\n }\n\n return null;\n }\n\n /** Extract physics-agnostic collision shapes from object layers. */\n getCollisionShapes(objectLayerName?: string): TilemapColliderConfig[] {\n return extractCollisionShapes(this.data, objectLayerName);\n }\n\n /** Objects from object layers grouped by `class ?? name`. Use a layer name to scope. */\n getObjects(objectLayerName?: string): Record<string, MapObject[]> {\n const filtered = objectLayerName\n ? this.data.objectLayers.filter((l) => l.name === objectLayerName)\n : this.data.objectLayers;\n\n const result: Record<string, MapObject[]> = {};\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const key = obj.class ?? obj.name;\n if (!result[key]) {\n result[key] = [];\n }\n result[key].push(obj);\n }\n }\n\n return result;\n }\n\n /** Flat list of every object across every object layer. Memoized — safe because parsed map data is immutable post-construction. */\n getAllObjects(): MapObject[] {\n if (this._allObjectsCache) return this._allObjectsCache;\n const result: MapObject[] = [];\n for (const layer of this.data.objectLayers) {\n for (const obj of layer.objects) result.push(obj);\n }\n this._allObjectsCache = result;\n return result;\n }\n\n /**\n * Iterate every object on the given layer (or every layer if omitted),\n * passing the auto-derived stable key alongside each object so callers can\n * spawn entities with `scene.spawn(Class, params, { key })`.\n *\n * Skips objects that don't have a key prefix (component constructed from raw\n * `map:` without `mapKey` or `keyPrefix`) — those callers should iterate\n * `getObjects` directly.\n */\n forEachObject(\n layerName: string | undefined,\n fn: (obj: MapObject, key: string) => void,\n ): void {\n if (this.keyPrefix === null) {\n throw new Error(\n \"TilemapComponent.forEachObject: cannot derive auto-keys without a `mapKey`, `source`, or explicit `keyPrefix`.\",\n );\n }\n const layers = layerName\n ? this.data.objectLayers.filter((l) => l.name === layerName)\n : this.data.objectLayers;\n for (const layer of layers) {\n for (const obj of layer.objects) {\n fn(obj, tiledObjectKey(this.keyPrefix, obj.id));\n }\n }\n }\n\n /** Auto-derived stable key for an object: `<keyPrefix>#object:<id>`. */\n objectKey(obj: MapObject): string {\n if (this.keyPrefix === null) {\n throw new Error(\n \"TilemapComponent.objectKey: cannot derive a key without a `mapKey`, `source`, or explicit `keyPrefix`.\",\n );\n }\n return tiledObjectKey(this.keyPrefix, obj.id);\n }\n\n /** Find an object by its Tiled `id`. Searches every object layer. */\n findObject(id: number): MapObject | undefined {\n for (const layer of this.data.objectLayers) {\n for (const obj of layer.objects) {\n if (obj.id === id) return obj;\n }\n }\n return undefined;\n }\n\n /** Find the first object with a matching `name`. Searches every object layer. */\n findObjectByName(name: string): MapObject | undefined {\n for (const layer of this.data.objectLayers) {\n for (const obj of layer.objects) {\n if (obj.name === name) return obj;\n }\n }\n return undefined;\n }\n\n /** Read a typed custom property off any tilemap object. */\n getProperty<T = unknown>(obj: MapObject, name: string): T | undefined {\n return getProperty<T>(obj, name);\n }\n\n /** Read an indexed property bag (`name[0]`, `name[1]`, ...) as an array. */\n getPropertyArray<T = unknown>(obj: MapObject, name: string): T[] {\n return getPropertyArray<T>(obj, name);\n }\n\n /**\n * Resolve a Tiled object-reference property to the actual object.\n * Auto-collects across every layer so callers don't have to.\n */\n resolveRef(obj: MapObject, propName: string): MapObject | undefined {\n return resolveObjectRef(obj, propName, this.getAllObjects());\n }\n\n /** Same as `resolveRef`, but for indexed object-reference arrays. */\n resolveRefArray(obj: MapObject, propName: string): MapObject[] {\n return resolveObjectRefArray(obj, propName, this.getAllObjects());\n }\n}\n","import { CompositeTilemap } from \"@pixi/tilemap\";\nimport { Assets, Texture, Rectangle } from \"pixi.js\";\nimport type {\n TiledMapData,\n TileLayer,\n TilesetRef,\n ObjectGroup,\n TileObject,\n} from \"./types.js\";\nimport type {\n TilemapData,\n TileLayerData,\n ObjectLayerData,\n MapObject,\n} from \"../types.js\";\n\n// ─── Generic adapter ────────────────────────────────────────────────\n\n/**\n * Convert Tiled JSON data to the generic TilemapData format.\n */\nexport function toTilemapData(map: TiledMapData): TilemapData {\n const tileLayers: TileLayerData[] = [];\n const objectLayers: ObjectLayerData[] = [];\n\n for (const layer of map.layers) {\n if (layer.type === \"tilelayer\") {\n tileLayers.push({\n name: layer.name,\n data: layer.data,\n width: layer.width,\n height: layer.height,\n visible: layer.visible,\n });\n } else if (layer.type === \"objectgroup\") {\n objectLayers.push({\n name: layer.name,\n objects: layer.objects.map(tiledObjectToMapObject),\n visible: layer.visible,\n });\n }\n }\n\n return {\n width: map.width,\n height: map.height,\n tileWidth: map.tilewidth,\n tileHeight: map.tileheight,\n tileLayers,\n objectLayers,\n };\n}\n\nfunction tiledObjectToMapObject(obj: TileObject): MapObject {\n const result: MapObject = {\n id: obj.id,\n name: obj.name,\n x: obj.x,\n y: obj.y,\n width: obj.width,\n height: obj.height,\n rotation: obj.rotation,\n visible: obj.visible,\n };\n\n const cls = obj.class ?? obj.type;\n if (cls) result.class = cls;\n if (obj.point === true) result.point = true;\n if (obj.polygon) result.polygon = obj.polygon;\n if (obj.properties) {\n result.properties = obj.properties.map((p) => ({\n name: p.name,\n type: p.type,\n value: p.value,\n }));\n }\n\n return result;\n}\n\n// ─── Tiled-specific rendering ───────────────────────────────────────\n\n/**\n * Resolve the tileset that owns a given global tile ID.\n * Tilesets are sorted by firstgid; we find the last tileset whose firstgid <= gid.\n */\nfunction findTileset(tilesets: TilesetRef[], gid: number): TilesetRef | null {\n let result: TilesetRef | null = null;\n for (const ts of tilesets) {\n if (ts.firstgid <= gid) {\n if (!result || ts.firstgid > result.firstgid) {\n result = ts;\n }\n }\n }\n return result;\n}\n\n/**\n * Resolve the texture for a tile given its GID and owning tileset.\n */\nfunction resolveTileTexture(\n gid: number,\n tileset: TilesetRef,\n): Texture | null {\n const data = tileset.data;\n if (!data) return null;\n const localId = gid - tileset.firstgid;\n\n if (data.tiles?.length) {\n // Collection-of-images tileset: look up texture by filename from cache\n const tileData = data.tiles[localId];\n if (!tileData?.image) return null;\n const filenameMatch = tileData.image.match(/[^/]*$/);\n const filename = filenameMatch?.[0];\n if (!filename) return null;\n const tex = Assets.get<Texture>(filename);\n return tex ?? null;\n }\n\n if (data.image) {\n // Single-image tileset: sub-textures were created by the loader\n const cacheKey = `${data.name}:${localId}`;\n const tex = Assets.get<Texture>(cacheKey);\n if (tex) return tex;\n\n // Fallback: create sub-texture on the fly from the base image\n const filenameMatch = data.image.match(/[^/]*$/);\n const filename = filenameMatch?.[0];\n if (!filename) return null;\n const baseTex = Assets.get<Texture>(filename);\n if (!baseTex) return null;\n\n const cols = data.columns;\n const tw = data.tilewidth;\n const th = data.tileheight;\n const margin = data.margin ?? 0;\n const spacing = data.spacing ?? 0;\n const col = localId % cols;\n const row = Math.floor(localId / cols);\n const x = margin + col * (tw + spacing);\n const y = margin + row * (th + spacing);\n\n return new Texture({\n source: baseTex.source,\n frame: new Rectangle(x, y, tw, th),\n });\n }\n\n return null;\n}\n\n/**\n * Build CompositeTilemap display objects from a parsed Tiled map.\n *\n * @param map - Parsed TiledMapData (with resolved tilesets).\n * @param layerNames - Optional filter: only process these tile layer names.\n * @returns Array of CompositeTilemap, one per tile layer.\n */\nexport function createTilemapLayers(\n map: TiledMapData,\n layerNames?: string[],\n): CompositeTilemap[] {\n const tileLayers = map.layers.filter(\n (l): l is TileLayer => l.type === \"tilelayer\",\n );\n\n const filtered = layerNames\n ? tileLayers.filter((l) => layerNames.includes(l.name))\n : tileLayers;\n\n return filtered.map((layer) => {\n const tilemap = new CompositeTilemap();\n const { data, width } = layer;\n\n for (let index = 0; index < data.length; index++) {\n const gid = data[index]!;\n if (gid === 0) continue;\n\n const tileset = findTileset(map.tilesets, gid);\n if (!tileset) {\n throw new Error(`No tileset found for tile GID ${gid}`);\n }\n\n const texture = resolveTileTexture(gid, tileset);\n if (!texture) {\n throw new Error(\n `Could not resolve texture for tile GID ${gid} in tileset \"${tileset.data?.name}\"`,\n );\n }\n\n const x = index % width;\n const y = Math.floor(index / width);\n tilemap.tile(texture, x * map.tilewidth, y * map.tileheight);\n }\n\n return tilemap;\n });\n}\n\n/**\n * Extract objects from Tiled object layers, grouped by class/type/name.\n *\n * @param map - Parsed TiledMapData.\n * @param objectLayerName - Optional: only extract from this layer.\n * @returns Record mapping class/type/name to arrays of TileObject.\n */\nexport function extractObjects(\n map: TiledMapData,\n objectLayerName?: string,\n): Record<string, TileObject[]> {\n const objectLayers = map.layers.filter(\n (l): l is ObjectGroup => l.type === \"objectgroup\",\n );\n\n const filtered = objectLayerName\n ? objectLayers.filter((l) => l.name === objectLayerName)\n : objectLayers;\n\n const result: Record<string, TileObject[]> = {};\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const key = obj.class ?? obj.type ?? obj.name;\n if (!result[key]) {\n result[key] = [];\n }\n result[key].push(obj);\n }\n }\n\n return result;\n}\n","import type {\n TilemapData,\n MapObject,\n TilemapColliderConfig,\n RectColliderConfig,\n PolygonColliderConfig,\n} from \"./types.js\";\n\n/**\n * Extract physics-agnostic collision shapes from object layers.\n *\n * - Rectangle objects -> RectColliderConfig\n * - Polygon objects -> PolygonColliderConfig\n * - Point objects -> skipped (not collision shapes)\n *\n * @param map - Generic TilemapData.\n * @param objectLayerName - Optional: only extract from this layer.\n */\nexport function extractCollisionShapes(\n map: TilemapData,\n objectLayerName?: string,\n): TilemapColliderConfig[] {\n const filtered = objectLayerName\n ? map.objectLayers.filter((l) => l.name === objectLayerName)\n : map.objectLayers;\n\n const shapes: TilemapColliderConfig[] = [];\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const shape = objectToColliderConfig(obj);\n if (shape) shapes.push(shape);\n }\n }\n\n return shapes;\n}\n\n/**\n * Convert a single MapObject to a ColliderConfig.\n * Returns null for point objects (not collision shapes).\n */\nfunction objectToColliderConfig(obj: MapObject): TilemapColliderConfig | null {\n // Skip point objects\n if (obj.point) return null;\n\n if (obj.polygon) {\n const config: PolygonColliderConfig = {\n type: \"polygon\",\n x: obj.x,\n y: obj.y,\n vertices: obj.polygon.map((v) => ({ x: v.x, y: v.y })),\n };\n return config;\n }\n\n // Rectangle object\n const config: RectColliderConfig = {\n type: \"rect\",\n x: obj.x,\n y: obj.y,\n width: obj.width,\n height: obj.height,\n };\n return config;\n}\n","/**\n * Build the stable identity key for an entity sourced from a Tiled object.\n *\n * Format: `<prefix>#object:<id>`. The prefix is normally the map's asset path\n * (e.g. `/assets/dungeon/dungeon-map.json#object:42`); pass an explicit prefix\n * when distinguishing between multiple instances of the same map.\n *\n * Use this to thread Tiled object identity into `scene.spawn(Class, params, { key })`\n * so persistent stores (`defineSet<string>`, `defineMap<string, T>`) can key off\n * authored level content without each game inventing its own naming scheme.\n */\nexport function tiledObjectKey(prefix: string, objectId: number): string {\n return `${prefix}#object:${objectId}`;\n}\n","import type { HasProperties, MapObject } from \"./types.js\";\n\n/**\n * Get a single property value by name.\n * Returns `undefined` if the property is not found.\n */\nexport function getProperty<T = unknown>(\n obj: HasProperties,\n name: string,\n): T | undefined {\n const prop = obj.properties?.find((p) => p.name === name);\n return prop?.value as T | undefined;\n}\n\n/**\n * Get a pseudo-array of property values.\n *\n * Tiled doesn't support array properties natively, so a common convention\n * is to use indexed names like `spawns[0]`, `spawns[1]`, etc.\n * This function collects them into a proper array, preserving index order.\n */\nexport function getPropertyArray<T = unknown>(\n obj: HasProperties,\n name: string,\n): T[] {\n const pattern = new RegExp(`^${escapeRegex(name)}\\\\[(\\\\d+)\\\\]$`);\n const values: T[] = [];\n\n if (!obj.properties) return values;\n\n for (const prop of obj.properties) {\n const match = prop.name.match(pattern);\n if (match) {\n const index = Number.parseInt(match[1]!, 10);\n values[index] = prop.value as T;\n }\n }\n\n return values;\n}\n\n/**\n * Resolve a property of `type: \"object\"` (an ID reference) to the actual MapObject.\n * Returns `undefined` if the property doesn't exist or the referenced object isn't found.\n */\nexport function resolveObjectRef(\n obj: HasProperties,\n propName: string,\n allObjects: MapObject[],\n): MapObject | undefined {\n const id = getProperty<number>(obj, propName);\n if (id === undefined) return undefined;\n return allObjects.find((o) => o.id === id);\n}\n\n/**\n * Resolve a pseudo-array of object ID references to actual MapObjects.\n * Uses the `name[0]`, `name[1]` convention.\n */\nexport function resolveObjectRefArray(\n obj: HasProperties,\n propName: string,\n allObjects: MapObject[],\n): MapObject[] {\n const ids = getPropertyArray<number>(obj, propName);\n return ids\n .map((id) => allObjects.find((o) => o.id === id))\n .filter((o): o is MapObject => o !== undefined);\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","import { AssetHandle } from \"@yagejs/core\";\nimport type { TiledMapData } from \"./tiled/types.js\";\n\n/** Create a typed asset handle for a Tiled map JSON. */\nexport function tiledMap(path: string): AssetHandle<TiledMapData> {\n return new AssetHandle(\"tiledMap\", path);\n}\n","import type { ColliderConfig as PhysicsColliderConfig } from \"@yagejs/physics\";\nimport type { TilemapColliderConfig } from \"./types.js\";\n\n/**\n * Convert tilemap TilemapColliderConfig[] (top-left origin rects/polygons) into\n * physics-package ColliderConfig[] (center-origin shape + offset).\n */\nexport function toPhysicsColliders(\n shapes: TilemapColliderConfig[],\n): PhysicsColliderConfig[] {\n return shapes.map(toPhysicsCollider);\n}\n\nfunction toPhysicsCollider(config: TilemapColliderConfig): PhysicsColliderConfig {\n switch (config.type) {\n case \"polygon\":\n return {\n shape: {\n type: \"polygon\",\n vertices: config.vertices,\n },\n offset: { x: config.x, y: config.y },\n };\n case \"rect\":\n return {\n shape: { type: \"box\", width: config.width, height: config.height },\n offset: {\n x: config.x + config.width / 2,\n y: config.y + config.height / 2,\n },\n };\n }\n}\n"],"mappings":"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","names":["import_core","import_pixi","import_core","import_pixi","import_pixi","config","path","import_core","path"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Plugin, EngineContext, SystemScheduler, Component, System, Phase, AssetHandle } from '@yagejs/core';
1
+ import { Plugin, EngineContext, SystemScheduler, Component, AssetHandle, System, Phase } from '@yagejs/core';
2
2
  import { Container, ExtensionType, LoaderParser } from 'pixi.js';
3
3
  import { ColliderConfig } from '@yagejs/physics';
4
4
  import { CompositeTilemap } from '@pixi/tilemap';
@@ -202,29 +202,44 @@ type TilemapColliderConfig = RectColliderConfig | PolygonColliderConfig;
202
202
 
203
203
  /** Options for creating a TilemapComponent. */
204
204
  interface TilemapComponentOptions {
205
- /** Parsed Tiled map data (not serializable). */
205
+ /** Asset handle for the map. Preferred — captures both the parsed data and the asset path. */
206
+ source?: AssetHandle<TiledMapData>;
207
+ /** Parsed Tiled map data. Use only when you don't have an AssetHandle. Save/load and auto-keys require `mapKey` or `source`. */
206
208
  map?: TiledMapData;
207
- /** Asset path to the Tiled JSON (serializable, resolved via Assets.get). */
209
+ /** Asset path to the Tiled JSON. Resolved via `Assets.get`. Save/load uses this. */
208
210
  mapKey?: string;
209
211
  /** Which tile layers to render. Omit to render all. */
210
212
  layers?: string[];
211
213
  /** Render layer name. Default: "default". */
212
214
  layer?: string;
215
+ /**
216
+ * Override prefix used when auto-keying entities spawned from Tiled objects.
217
+ * Defaults to `mapKey`. Set this when multiple instances of the same map need
218
+ * distinct entity-key namespaces (e.g. instanced dungeons).
219
+ */
220
+ keyPrefix?: string;
213
221
  }
214
222
  /** Serializable snapshot of a TilemapComponent. */
215
223
  interface TilemapComponentData {
216
224
  mapKey: string;
217
225
  layers?: string[];
218
226
  layer: string;
227
+ keyPrefix?: string;
219
228
  }
220
229
  /** Component that renders a Tiled map using @pixi/tilemap. */
221
230
  declare class TilemapComponent extends Component {
222
231
  readonly container: Container;
223
232
  readonly data: TilemapData;
233
+ /** Asset path of this map, or `null` if constructed from a raw `TiledMapData` without one. */
234
+ readonly mapKey: string | null;
235
+ /** Prefix used to derive auto-keys for entities spawned from objects. */
236
+ readonly keyPrefix: string | null;
224
237
  private readonly _tiledMap;
225
- private readonly _mapKey;
226
238
  private readonly layerNames;
227
239
  private readonly renderLayerName;
240
+ private readonly _explicitKeyPrefix;
241
+ /** Lazy flat-list cache. The parsed map is treated as immutable post-construction; if that ever changes, callers must invalidate. */
242
+ private _allObjectsCache;
228
243
  constructor(options: TilemapComponentOptions);
229
244
  onAdd(): void;
230
245
  onDestroy(): void;
@@ -245,8 +260,37 @@ declare class TilemapComponent extends Component {
245
260
  getTileAt(worldX: number, worldY: number, layerName?: string): number | null;
246
261
  /** Extract physics-agnostic collision shapes from object layers. */
247
262
  getCollisionShapes(objectLayerName?: string): TilemapColliderConfig[];
248
- /** Extract objects from object layers grouped by class/name. */
263
+ /** Objects from object layers grouped by `class ?? name`. Use a layer name to scope. */
249
264
  getObjects(objectLayerName?: string): Record<string, MapObject[]>;
265
+ /** Flat list of every object across every object layer. Memoized — safe because parsed map data is immutable post-construction. */
266
+ getAllObjects(): MapObject[];
267
+ /**
268
+ * Iterate every object on the given layer (or every layer if omitted),
269
+ * passing the auto-derived stable key alongside each object so callers can
270
+ * spawn entities with `scene.spawn(Class, params, { key })`.
271
+ *
272
+ * Skips objects that don't have a key prefix (component constructed from raw
273
+ * `map:` without `mapKey` or `keyPrefix`) — those callers should iterate
274
+ * `getObjects` directly.
275
+ */
276
+ forEachObject(layerName: string | undefined, fn: (obj: MapObject, key: string) => void): void;
277
+ /** Auto-derived stable key for an object: `<keyPrefix>#object:<id>`. */
278
+ objectKey(obj: MapObject): string;
279
+ /** Find an object by its Tiled `id`. Searches every object layer. */
280
+ findObject(id: number): MapObject | undefined;
281
+ /** Find the first object with a matching `name`. Searches every object layer. */
282
+ findObjectByName(name: string): MapObject | undefined;
283
+ /** Read a typed custom property off any tilemap object. */
284
+ getProperty<T = unknown>(obj: MapObject, name: string): T | undefined;
285
+ /** Read an indexed property bag (`name[0]`, `name[1]`, ...) as an array. */
286
+ getPropertyArray<T = unknown>(obj: MapObject, name: string): T[];
287
+ /**
288
+ * Resolve a Tiled object-reference property to the actual object.
289
+ * Auto-collects across every layer so callers don't have to.
290
+ */
291
+ resolveRef(obj: MapObject, propName: string): MapObject | undefined;
292
+ /** Same as `resolveRef`, but for indexed object-reference arrays. */
293
+ resolveRefArray(obj: MapObject, propName: string): MapObject[];
250
294
  }
251
295
 
252
296
  /** Syncs Transform to TilemapComponent display containers. */
@@ -261,6 +305,19 @@ declare class TilemapRenderSystem extends System {
261
305
  /** Create a typed asset handle for a Tiled map JSON. */
262
306
  declare function tiledMap(path: string): AssetHandle<TiledMapData>;
263
307
 
308
+ /**
309
+ * Build the stable identity key for an entity sourced from a Tiled object.
310
+ *
311
+ * Format: `<prefix>#object:<id>`. The prefix is normally the map's asset path
312
+ * (e.g. `/assets/dungeon/dungeon-map.json#object:42`); pass an explicit prefix
313
+ * when distinguishing between multiple instances of the same map.
314
+ *
315
+ * Use this to thread Tiled object identity into `scene.spawn(Class, params, { key })`
316
+ * so persistent stores (`defineSet<string>`, `defineMap<string, T>`) can key off
317
+ * authored level content without each game inventing its own naming scheme.
318
+ */
319
+ declare function tiledObjectKey(prefix: string, objectId: number): string;
320
+
264
321
  /**
265
322
  * Extract physics-agnostic collision shapes from object layers.
266
323
  *
@@ -330,4 +387,4 @@ declare function createTilemapLayers(map: TiledMapData, layerNames?: string[]):
330
387
  */
331
388
  declare function extractObjects(map: TiledMapData, objectLayerName?: string): Record<string, TileObject[]>;
332
389
 
333
- export { type HasProperties, type MapObject, type MapObjectProperty, type ObjectGroup, type ObjectLayerData, type PointObject, type PolygonColliderConfig, type PolygonObject, type RectColliderConfig, type RectangleObject, type TileData, type TileLayer, type TileLayerData, type TileObject, type TileObjectProperty, type TiledMapData, type TilemapColliderConfig, TilemapComponent, type TilemapComponentData, type TilemapComponentOptions, type TilemapData, TilemapPlugin, TilemapRenderSystem, type TilesetData, type TilesetRef, createTilemapLayers, extractCollisionShapes, extractObjects, getProperty, getPropertyArray, resolveObjectRef, resolveObjectRefArray, tiledMap, tiledMapAssetExtension, toPhysicsColliders, toTilemapData };
390
+ export { type HasProperties, type MapObject, type MapObjectProperty, type ObjectGroup, type ObjectLayerData, type PointObject, type PolygonColliderConfig, type PolygonObject, type RectColliderConfig, type RectangleObject, type TileData, type TileLayer, type TileLayerData, type TileObject, type TileObjectProperty, type TiledMapData, type TilemapColliderConfig, TilemapComponent, type TilemapComponentData, type TilemapComponentOptions, type TilemapData, TilemapPlugin, TilemapRenderSystem, type TilesetData, type TilesetRef, createTilemapLayers, extractCollisionShapes, extractObjects, getProperty, getPropertyArray, resolveObjectRef, resolveObjectRefArray, tiledMap, tiledMapAssetExtension, tiledObjectKey, toPhysicsColliders, toTilemapData };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Plugin, EngineContext, SystemScheduler, Component, System, Phase, AssetHandle } from '@yagejs/core';
1
+ import { Plugin, EngineContext, SystemScheduler, Component, AssetHandle, System, Phase } from '@yagejs/core';
2
2
  import { Container, ExtensionType, LoaderParser } from 'pixi.js';
3
3
  import { ColliderConfig } from '@yagejs/physics';
4
4
  import { CompositeTilemap } from '@pixi/tilemap';
@@ -202,29 +202,44 @@ type TilemapColliderConfig = RectColliderConfig | PolygonColliderConfig;
202
202
 
203
203
  /** Options for creating a TilemapComponent. */
204
204
  interface TilemapComponentOptions {
205
- /** Parsed Tiled map data (not serializable). */
205
+ /** Asset handle for the map. Preferred — captures both the parsed data and the asset path. */
206
+ source?: AssetHandle<TiledMapData>;
207
+ /** Parsed Tiled map data. Use only when you don't have an AssetHandle. Save/load and auto-keys require `mapKey` or `source`. */
206
208
  map?: TiledMapData;
207
- /** Asset path to the Tiled JSON (serializable, resolved via Assets.get). */
209
+ /** Asset path to the Tiled JSON. Resolved via `Assets.get`. Save/load uses this. */
208
210
  mapKey?: string;
209
211
  /** Which tile layers to render. Omit to render all. */
210
212
  layers?: string[];
211
213
  /** Render layer name. Default: "default". */
212
214
  layer?: string;
215
+ /**
216
+ * Override prefix used when auto-keying entities spawned from Tiled objects.
217
+ * Defaults to `mapKey`. Set this when multiple instances of the same map need
218
+ * distinct entity-key namespaces (e.g. instanced dungeons).
219
+ */
220
+ keyPrefix?: string;
213
221
  }
214
222
  /** Serializable snapshot of a TilemapComponent. */
215
223
  interface TilemapComponentData {
216
224
  mapKey: string;
217
225
  layers?: string[];
218
226
  layer: string;
227
+ keyPrefix?: string;
219
228
  }
220
229
  /** Component that renders a Tiled map using @pixi/tilemap. */
221
230
  declare class TilemapComponent extends Component {
222
231
  readonly container: Container;
223
232
  readonly data: TilemapData;
233
+ /** Asset path of this map, or `null` if constructed from a raw `TiledMapData` without one. */
234
+ readonly mapKey: string | null;
235
+ /** Prefix used to derive auto-keys for entities spawned from objects. */
236
+ readonly keyPrefix: string | null;
224
237
  private readonly _tiledMap;
225
- private readonly _mapKey;
226
238
  private readonly layerNames;
227
239
  private readonly renderLayerName;
240
+ private readonly _explicitKeyPrefix;
241
+ /** Lazy flat-list cache. The parsed map is treated as immutable post-construction; if that ever changes, callers must invalidate. */
242
+ private _allObjectsCache;
228
243
  constructor(options: TilemapComponentOptions);
229
244
  onAdd(): void;
230
245
  onDestroy(): void;
@@ -245,8 +260,37 @@ declare class TilemapComponent extends Component {
245
260
  getTileAt(worldX: number, worldY: number, layerName?: string): number | null;
246
261
  /** Extract physics-agnostic collision shapes from object layers. */
247
262
  getCollisionShapes(objectLayerName?: string): TilemapColliderConfig[];
248
- /** Extract objects from object layers grouped by class/name. */
263
+ /** Objects from object layers grouped by `class ?? name`. Use a layer name to scope. */
249
264
  getObjects(objectLayerName?: string): Record<string, MapObject[]>;
265
+ /** Flat list of every object across every object layer. Memoized — safe because parsed map data is immutable post-construction. */
266
+ getAllObjects(): MapObject[];
267
+ /**
268
+ * Iterate every object on the given layer (or every layer if omitted),
269
+ * passing the auto-derived stable key alongside each object so callers can
270
+ * spawn entities with `scene.spawn(Class, params, { key })`.
271
+ *
272
+ * Skips objects that don't have a key prefix (component constructed from raw
273
+ * `map:` without `mapKey` or `keyPrefix`) — those callers should iterate
274
+ * `getObjects` directly.
275
+ */
276
+ forEachObject(layerName: string | undefined, fn: (obj: MapObject, key: string) => void): void;
277
+ /** Auto-derived stable key for an object: `<keyPrefix>#object:<id>`. */
278
+ objectKey(obj: MapObject): string;
279
+ /** Find an object by its Tiled `id`. Searches every object layer. */
280
+ findObject(id: number): MapObject | undefined;
281
+ /** Find the first object with a matching `name`. Searches every object layer. */
282
+ findObjectByName(name: string): MapObject | undefined;
283
+ /** Read a typed custom property off any tilemap object. */
284
+ getProperty<T = unknown>(obj: MapObject, name: string): T | undefined;
285
+ /** Read an indexed property bag (`name[0]`, `name[1]`, ...) as an array. */
286
+ getPropertyArray<T = unknown>(obj: MapObject, name: string): T[];
287
+ /**
288
+ * Resolve a Tiled object-reference property to the actual object.
289
+ * Auto-collects across every layer so callers don't have to.
290
+ */
291
+ resolveRef(obj: MapObject, propName: string): MapObject | undefined;
292
+ /** Same as `resolveRef`, but for indexed object-reference arrays. */
293
+ resolveRefArray(obj: MapObject, propName: string): MapObject[];
250
294
  }
251
295
 
252
296
  /** Syncs Transform to TilemapComponent display containers. */
@@ -261,6 +305,19 @@ declare class TilemapRenderSystem extends System {
261
305
  /** Create a typed asset handle for a Tiled map JSON. */
262
306
  declare function tiledMap(path: string): AssetHandle<TiledMapData>;
263
307
 
308
+ /**
309
+ * Build the stable identity key for an entity sourced from a Tiled object.
310
+ *
311
+ * Format: `<prefix>#object:<id>`. The prefix is normally the map's asset path
312
+ * (e.g. `/assets/dungeon/dungeon-map.json#object:42`); pass an explicit prefix
313
+ * when distinguishing between multiple instances of the same map.
314
+ *
315
+ * Use this to thread Tiled object identity into `scene.spawn(Class, params, { key })`
316
+ * so persistent stores (`defineSet<string>`, `defineMap<string, T>`) can key off
317
+ * authored level content without each game inventing its own naming scheme.
318
+ */
319
+ declare function tiledObjectKey(prefix: string, objectId: number): string;
320
+
264
321
  /**
265
322
  * Extract physics-agnostic collision shapes from object layers.
266
323
  *
@@ -330,4 +387,4 @@ declare function createTilemapLayers(map: TiledMapData, layerNames?: string[]):
330
387
  */
331
388
  declare function extractObjects(map: TiledMapData, objectLayerName?: string): Record<string, TileObject[]>;
332
389
 
333
- export { type HasProperties, type MapObject, type MapObjectProperty, type ObjectGroup, type ObjectLayerData, type PointObject, type PolygonColliderConfig, type PolygonObject, type RectColliderConfig, type RectangleObject, type TileData, type TileLayer, type TileLayerData, type TileObject, type TileObjectProperty, type TiledMapData, type TilemapColliderConfig, TilemapComponent, type TilemapComponentData, type TilemapComponentOptions, type TilemapData, TilemapPlugin, TilemapRenderSystem, type TilesetData, type TilesetRef, createTilemapLayers, extractCollisionShapes, extractObjects, getProperty, getPropertyArray, resolveObjectRef, resolveObjectRefArray, tiledMap, tiledMapAssetExtension, toPhysicsColliders, toTilemapData };
390
+ export { type HasProperties, type MapObject, type MapObjectProperty, type ObjectGroup, type ObjectLayerData, type PointObject, type PolygonColliderConfig, type PolygonObject, type RectColliderConfig, type RectangleObject, type TileData, type TileLayer, type TileLayerData, type TileObject, type TileObjectProperty, type TiledMapData, type TilemapColliderConfig, TilemapComponent, type TilemapComponentData, type TilemapComponentOptions, type TilemapData, TilemapPlugin, TilemapRenderSystem, type TilesetData, type TilesetRef, createTilemapLayers, extractCollisionShapes, extractObjects, getProperty, getPropertyArray, resolveObjectRef, resolveObjectRefArray, tiledMap, tiledMapAssetExtension, tiledObjectKey, toPhysicsColliders, toTilemapData };
package/dist/index.js CHANGED
@@ -321,6 +321,48 @@ function objectToColliderConfig(obj) {
321
321
  }
322
322
  __name(objectToColliderConfig, "objectToColliderConfig");
323
323
 
324
+ // src/keys.ts
325
+ function tiledObjectKey(prefix, objectId) {
326
+ return `${prefix}#object:${objectId}`;
327
+ }
328
+ __name(tiledObjectKey, "tiledObjectKey");
329
+
330
+ // src/properties.ts
331
+ function getProperty(obj, name) {
332
+ const prop = obj.properties?.find((p) => p.name === name);
333
+ return prop?.value;
334
+ }
335
+ __name(getProperty, "getProperty");
336
+ function getPropertyArray(obj, name) {
337
+ const pattern = new RegExp(`^${escapeRegex(name)}\\[(\\d+)\\]$`);
338
+ const values = [];
339
+ if (!obj.properties) return values;
340
+ for (const prop of obj.properties) {
341
+ const match = prop.name.match(pattern);
342
+ if (match) {
343
+ const index = Number.parseInt(match[1], 10);
344
+ values[index] = prop.value;
345
+ }
346
+ }
347
+ return values;
348
+ }
349
+ __name(getPropertyArray, "getPropertyArray");
350
+ function resolveObjectRef(obj, propName, allObjects) {
351
+ const id = getProperty(obj, propName);
352
+ if (id === void 0) return void 0;
353
+ return allObjects.find((o) => o.id === id);
354
+ }
355
+ __name(resolveObjectRef, "resolveObjectRef");
356
+ function resolveObjectRefArray(obj, propName, allObjects) {
357
+ const ids = getPropertyArray(obj, propName);
358
+ return ids.map((id) => allObjects.find((o) => o.id === id)).filter((o) => o !== void 0);
359
+ }
360
+ __name(resolveObjectRefArray, "resolveObjectRefArray");
361
+ function escapeRegex(str) {
362
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
363
+ }
364
+ __name(escapeRegex, "escapeRegex");
365
+
324
366
  // src/TilemapComponent.ts
325
367
  var _TilemapComponent_decorators, _init, _a;
326
368
  _TilemapComponent_decorators = [serializable];
@@ -330,28 +372,51 @@ var _TilemapComponent = class _TilemapComponent extends (_a = Component) {
330
372
  }
331
373
  container;
332
374
  data;
375
+ /** Asset path of this map, or `null` if constructed from a raw `TiledMapData` without one. */
376
+ mapKey;
377
+ /** Prefix used to derive auto-keys for entities spawned from objects. */
378
+ keyPrefix;
333
379
  _tiledMap;
334
- _mapKey;
335
380
  layerNames;
336
381
  renderLayerName;
382
+ _explicitKeyPrefix;
383
+ /** Lazy flat-list cache. The parsed map is treated as immutable post-construction; if that ever changes, callers must invalidate. */
384
+ _allObjectsCache;
337
385
  constructor(options) {
338
386
  super();
339
- if (!options.map && !options.mapKey) {
387
+ const sourceCount = (options.source ? 1 : 0) + (options.map ? 1 : 0) + (options.mapKey ? 1 : 0);
388
+ if (sourceCount === 0) {
340
389
  throw new Error(
341
- "TilemapComponent requires either `map` or `mapKey`."
390
+ "TilemapComponent requires one of `source`, `map`, or `mapKey`."
342
391
  );
343
392
  }
344
- this._mapKey = options.mapKey ?? null;
345
- const tiledMap2 = options.map ?? Assets3.get(options.mapKey);
346
- if (!tiledMap2) {
347
- throw new Error(
348
- `TilemapComponent: map "${options.mapKey}" is not loaded. Add it to scene preload.`
349
- );
393
+ if (options.source) {
394
+ this.mapKey = options.source.path;
395
+ const data = Assets3.get(options.source.path);
396
+ if (!data) {
397
+ throw new Error(
398
+ `TilemapComponent: source "${options.source.path}" is not loaded. Add it to scene preload.`
399
+ );
400
+ }
401
+ this._tiledMap = data;
402
+ } else if (options.mapKey) {
403
+ this.mapKey = options.mapKey;
404
+ const data = Assets3.get(options.mapKey);
405
+ if (!data) {
406
+ throw new Error(
407
+ `TilemapComponent: map "${options.mapKey}" is not loaded. Add it to scene preload.`
408
+ );
409
+ }
410
+ this._tiledMap = data;
411
+ } else {
412
+ this.mapKey = null;
413
+ this._tiledMap = options.map;
350
414
  }
351
- this._tiledMap = tiledMap2;
352
- this.data = toTilemapData(tiledMap2);
415
+ this.data = toTilemapData(this._tiledMap);
353
416
  this.layerNames = options.layers;
354
417
  this.renderLayerName = options.layer ?? "default";
418
+ this._explicitKeyPrefix = options.keyPrefix;
419
+ this.keyPrefix = options.keyPrefix ?? this.mapKey;
355
420
  this.container = new Container();
356
421
  }
357
422
  onAdd() {
@@ -367,23 +432,27 @@ var _TilemapComponent = class _TilemapComponent extends (_a = Component) {
367
432
  this.container.destroy({ children: true });
368
433
  }
369
434
  serialize() {
370
- if (!this._mapKey) {
435
+ if (!this.mapKey) {
371
436
  console.warn(
372
- `TilemapComponent on "${this.entity?.name}": created with a TiledMapData object. Use { mapKey } for save/load support.`
437
+ `TilemapComponent on "${this.entity?.name}": created with a TiledMapData object. Use { source } or { mapKey } for save/load support.`
373
438
  );
374
439
  return null;
375
440
  }
376
441
  return {
377
- mapKey: this._mapKey,
442
+ mapKey: this.mapKey,
378
443
  layer: this.renderLayerName,
379
- ...this.layerNames && { layers: this.layerNames }
444
+ ...this.layerNames && { layers: this.layerNames },
445
+ ...this._explicitKeyPrefix !== void 0 && {
446
+ keyPrefix: this._explicitKeyPrefix
447
+ }
380
448
  };
381
449
  }
382
450
  static fromSnapshot(data) {
383
451
  return new _TilemapComponent({
384
452
  mapKey: data.mapKey,
385
453
  layer: data.layer,
386
- ...data.layers && { layers: data.layers }
454
+ ...data.layers && { layers: data.layers },
455
+ ...data.keyPrefix !== void 0 && { keyPrefix: data.keyPrefix }
387
456
  });
388
457
  }
389
458
  /** Map width in pixels. */
@@ -428,7 +497,7 @@ var _TilemapComponent = class _TilemapComponent extends (_a = Component) {
428
497
  getCollisionShapes(objectLayerName) {
429
498
  return extractCollisionShapes(this.data, objectLayerName);
430
499
  }
431
- /** Extract objects from object layers grouped by class/name. */
500
+ /** Objects from object layers grouped by `class ?? name`. Use a layer name to scope. */
432
501
  getObjects(objectLayerName) {
433
502
  const filtered = objectLayerName ? this.data.objectLayers.filter((l) => l.name === objectLayerName) : this.data.objectLayers;
434
503
  const result = {};
@@ -443,6 +512,84 @@ var _TilemapComponent = class _TilemapComponent extends (_a = Component) {
443
512
  }
444
513
  return result;
445
514
  }
515
+ /** Flat list of every object across every object layer. Memoized — safe because parsed map data is immutable post-construction. */
516
+ getAllObjects() {
517
+ if (this._allObjectsCache) return this._allObjectsCache;
518
+ const result = [];
519
+ for (const layer of this.data.objectLayers) {
520
+ for (const obj of layer.objects) result.push(obj);
521
+ }
522
+ this._allObjectsCache = result;
523
+ return result;
524
+ }
525
+ /**
526
+ * Iterate every object on the given layer (or every layer if omitted),
527
+ * passing the auto-derived stable key alongside each object so callers can
528
+ * spawn entities with `scene.spawn(Class, params, { key })`.
529
+ *
530
+ * Skips objects that don't have a key prefix (component constructed from raw
531
+ * `map:` without `mapKey` or `keyPrefix`) — those callers should iterate
532
+ * `getObjects` directly.
533
+ */
534
+ forEachObject(layerName, fn) {
535
+ if (this.keyPrefix === null) {
536
+ throw new Error(
537
+ "TilemapComponent.forEachObject: cannot derive auto-keys without a `mapKey`, `source`, or explicit `keyPrefix`."
538
+ );
539
+ }
540
+ const layers = layerName ? this.data.objectLayers.filter((l) => l.name === layerName) : this.data.objectLayers;
541
+ for (const layer of layers) {
542
+ for (const obj of layer.objects) {
543
+ fn(obj, tiledObjectKey(this.keyPrefix, obj.id));
544
+ }
545
+ }
546
+ }
547
+ /** Auto-derived stable key for an object: `<keyPrefix>#object:<id>`. */
548
+ objectKey(obj) {
549
+ if (this.keyPrefix === null) {
550
+ throw new Error(
551
+ "TilemapComponent.objectKey: cannot derive a key without a `mapKey`, `source`, or explicit `keyPrefix`."
552
+ );
553
+ }
554
+ return tiledObjectKey(this.keyPrefix, obj.id);
555
+ }
556
+ /** Find an object by its Tiled `id`. Searches every object layer. */
557
+ findObject(id) {
558
+ for (const layer of this.data.objectLayers) {
559
+ for (const obj of layer.objects) {
560
+ if (obj.id === id) return obj;
561
+ }
562
+ }
563
+ return void 0;
564
+ }
565
+ /** Find the first object with a matching `name`. Searches every object layer. */
566
+ findObjectByName(name) {
567
+ for (const layer of this.data.objectLayers) {
568
+ for (const obj of layer.objects) {
569
+ if (obj.name === name) return obj;
570
+ }
571
+ }
572
+ return void 0;
573
+ }
574
+ /** Read a typed custom property off any tilemap object. */
575
+ getProperty(obj, name) {
576
+ return getProperty(obj, name);
577
+ }
578
+ /** Read an indexed property bag (`name[0]`, `name[1]`, ...) as an array. */
579
+ getPropertyArray(obj, name) {
580
+ return getPropertyArray(obj, name);
581
+ }
582
+ /**
583
+ * Resolve a Tiled object-reference property to the actual object.
584
+ * Auto-collects across every layer so callers don't have to.
585
+ */
586
+ resolveRef(obj, propName) {
587
+ return resolveObjectRef(obj, propName, this.getAllObjects());
588
+ }
589
+ /** Same as `resolveRef`, but for indexed object-reference arrays. */
590
+ resolveRefArray(obj, propName) {
591
+ return resolveObjectRefArray(obj, propName, this.getAllObjects());
592
+ }
446
593
  };
447
594
  _init = __decoratorStart(_a);
448
595
  _TilemapComponent = __decorateElement(_init, 0, "TilemapComponent", _TilemapComponent_decorators, _TilemapComponent);
@@ -532,42 +679,6 @@ function toPhysicsCollider(config) {
532
679
  }
533
680
  }
534
681
  __name(toPhysicsCollider, "toPhysicsCollider");
535
-
536
- // src/properties.ts
537
- function getProperty(obj, name) {
538
- const prop = obj.properties?.find((p) => p.name === name);
539
- return prop?.value;
540
- }
541
- __name(getProperty, "getProperty");
542
- function getPropertyArray(obj, name) {
543
- const pattern = new RegExp(`^${escapeRegex(name)}\\[(\\d+)\\]$`);
544
- const values = [];
545
- if (!obj.properties) return values;
546
- for (const prop of obj.properties) {
547
- const match = prop.name.match(pattern);
548
- if (match) {
549
- const index = Number.parseInt(match[1], 10);
550
- values[index] = prop.value;
551
- }
552
- }
553
- return values;
554
- }
555
- __name(getPropertyArray, "getPropertyArray");
556
- function resolveObjectRef(obj, propName, allObjects) {
557
- const id = getProperty(obj, propName);
558
- if (id === void 0) return void 0;
559
- return allObjects.find((o) => o.id === id);
560
- }
561
- __name(resolveObjectRef, "resolveObjectRef");
562
- function resolveObjectRefArray(obj, propName, allObjects) {
563
- const ids = getPropertyArray(obj, propName);
564
- return ids.map((id) => allObjects.find((o) => o.id === id)).filter((o) => o !== void 0);
565
- }
566
- __name(resolveObjectRefArray, "resolveObjectRefArray");
567
- function escapeRegex(str) {
568
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
569
- }
570
- __name(escapeRegex, "escapeRegex");
571
682
  export {
572
683
  TilemapComponent,
573
684
  TilemapPlugin,
@@ -581,6 +692,7 @@ export {
581
692
  resolveObjectRefArray,
582
693
  tiledMap,
583
694
  tiledMapAssetExtension,
695
+ tiledObjectKey,
584
696
  toPhysicsColliders,
585
697
  toTilemapData
586
698
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/TilemapPlugin.ts","../src/tiled/tiledMapLoader.ts","../src/TilemapRenderSystem.ts","../src/TilemapComponent.ts","../src/tiled/parseTiledMap.ts","../src/colliders.ts","../src/assets.ts","../src/toPhysicsColliders.ts","../src/properties.ts"],"sourcesContent":["import { AssetManagerKey } from \"@yagejs/core\";\nimport type { EngineContext, Plugin, SystemScheduler } from \"@yagejs/core\";\nimport { extensions, Assets } from \"pixi.js\";\nimport { tiledMapAssetExtension } from \"./tiled/tiledMapLoader.js\";\nimport { TilemapRenderSystem } from \"./TilemapRenderSystem.js\";\nimport type { TiledMapData } from \"./tiled/types.js\";\n\n/** Plugin that adds Tiled map loading and rendering to YAGE. */\nexport class TilemapPlugin implements Plugin {\n readonly name = \"tilemap\";\n readonly version = \"2.0.0\";\n readonly dependencies = [\"renderer\"] as const;\n\n install(context: EngineContext): void {\n // Register PixiJS loader extension for Tiled map JSON files\n extensions.add(tiledMapAssetExtension);\n\n // Register \"tiledMap\" loader with AssetManager\n const am = context.tryResolve(AssetManagerKey);\n am?.registerLoader(\"tiledMap\", {\n load: (path: string) => Assets.load<TiledMapData>(path),\n unload: (path: string) => {\n Assets.unload(path);\n },\n });\n }\n\n registerSystems(scheduler: SystemScheduler): void {\n scheduler.add(new TilemapRenderSystem());\n }\n}\n","import {\n ExtensionType,\n LoaderParserPriority,\n Assets,\n path,\n Texture,\n Rectangle,\n} from \"pixi.js\";\nimport type { LoaderParser, ResolvedAsset, Loader } from \"pixi.js\";\nimport type { TiledMapData, TilesetData, TilesetRef } from \"./types.js\";\n\n/**\n * PixiJS loader extension that detects Tiled map JSON files and resolves\n * their tileset references.\n *\n * Supports two tileset formats:\n * 1. **Collection-of-images** — tileset has `tiles[]` with image paths.\n * Assumes textures are already in the PixiJS cache (e.g. from a\n * pre-loaded spritesheet atlas).\n * 2. **Single-image tileset** — tileset has an `image` property pointing\n * to a spritesheet. The loader loads the image and creates sub-textures\n * for each tile based on grid layout.\n */\nconst tiledMapLoaderParser: LoaderParser<TiledMapData> = {\n id: \"tiledMapLoader\",\n\n extension: {\n type: ExtensionType.LoadParser,\n priority: LoaderParserPriority.High,\n },\n\n async testParse(\n asset: TiledMapData,\n resolvedAsset?: ResolvedAsset,\n ): Promise<boolean> {\n if (!resolvedAsset?.src) return false;\n if (path.extname(resolvedAsset.src).toLowerCase() !== \".json\") return false;\n const obj = asset as unknown as Record<string, unknown>;\n return !!(obj.tilesets && obj.layers);\n },\n\n async parse(\n asset: TiledMapData,\n resolvedAsset?: ResolvedAsset,\n loader?: Loader,\n ): Promise<TiledMapData> {\n const src = resolvedAsset?.src;\n if (!src || !loader) return asset;\n\n let basePath = path.dirname(src);\n if (basePath && !basePath.endsWith(\"/\")) {\n basePath += \"/\";\n }\n\n for (const tilesetRef of asset.tilesets as TilesetRef[]) {\n if (tilesetRef.source) {\n // External tileset JSON — load it\n const tilesetPath = basePath + tilesetRef.source;\n const tilesetData = (await loader.load<TilesetData>({\n src: tilesetPath,\n })) as TilesetData;\n tilesetRef.data = tilesetData;\n }\n\n const tileset = tilesetRef.data;\n if (!tileset) continue;\n\n // Single-image tileset: load the image and create sub-textures\n if (tileset.image && !tileset.tiles?.length) {\n const imagePath = basePath + tileset.image;\n const baseTexture = await Assets.load<Texture>(imagePath);\n const cols = tileset.columns;\n const tw = tileset.tilewidth;\n const th = tileset.tileheight;\n const margin = tileset.margin ?? 0;\n const spacing = tileset.spacing ?? 0;\n\n for (let id = 0; id < tileset.tilecount; id++) {\n const col = id % cols;\n const row = Math.floor(id / cols);\n const x = margin + col * (tw + spacing);\n const y = margin + row * (th + spacing);\n\n const frame = new Rectangle(x, y, tw, th);\n const subtex = new Texture({\n source: baseTexture.source,\n frame,\n });\n\n // Store subtexture in PixiJS cache with a key like \"tileset-name:id\"\n const cacheKey = `${tileset.name}:${id}`;\n Assets.cache.set(cacheKey, subtex);\n }\n }\n // Collection-of-images: textures are expected to already be\n // in the PixiJS cache (loaded via spritesheet atlas).\n }\n\n return asset;\n },\n\n unload() {},\n};\n\n/** PixiJS asset extension bundle for Tiled map JSON files. */\nexport const tiledMapAssetExtension = {\n extension: ExtensionType.Asset,\n loader: tiledMapLoaderParser,\n};\n","import { System, Phase, Transform, QueryCacheKey } from \"@yagejs/core\";\nimport type { EngineContext, QueryResult } from \"@yagejs/core\";\nimport { TilemapComponent } from \"./TilemapComponent.js\";\n\n/** Syncs Transform to TilemapComponent display containers. */\nexport class TilemapRenderSystem extends System {\n readonly phase = Phase.Render;\n readonly priority = -1; // Before DisplaySystem (0), so tilemaps render behind sprites\n\n private query!: QueryResult;\n\n onRegister(context: EngineContext): void {\n const queryCache = context.resolve(QueryCacheKey);\n this.query = queryCache.register([Transform, TilemapComponent]);\n }\n\n update(): void {\n for (const entity of this.query) {\n const transform = entity.get(Transform);\n const tilemap = entity.get(TilemapComponent);\n if (!tilemap.enabled) continue;\n\n tilemap.container.position.x = transform.worldPosition.x;\n tilemap.container.position.y = transform.worldPosition.y;\n tilemap.container.rotation = transform.worldRotation;\n tilemap.container.scale.x = transform.worldScale.x;\n tilemap.container.scale.y = transform.worldScale.y;\n }\n }\n}\n","import { Component, Transform, serializable } from \"@yagejs/core\";\nimport { Assets, Container } from \"pixi.js\";\nimport { SceneRenderTreeKey } from \"@yagejs/renderer\";\nimport { createTilemapLayers, toTilemapData } from \"./tiled/parseTiledMap.js\";\nimport { extractCollisionShapes } from \"./colliders.js\";\nimport type { TiledMapData } from \"./tiled/types.js\";\nimport type {\n TilemapData,\n MapObject,\n TilemapColliderConfig,\n} from \"./types.js\";\n\n/** Options for creating a TilemapComponent. */\nexport interface TilemapComponentOptions {\n /** Parsed Tiled map data (not serializable). */\n map?: TiledMapData;\n /** Asset path to the Tiled JSON (serializable, resolved via Assets.get). */\n mapKey?: string;\n /** Which tile layers to render. Omit to render all. */\n layers?: string[];\n /** Render layer name. Default: \"default\". */\n layer?: string;\n}\n\n/** Serializable snapshot of a TilemapComponent. */\nexport interface TilemapComponentData {\n mapKey: string;\n layers?: string[];\n layer: string;\n}\n\n/** Component that renders a Tiled map using @pixi/tilemap. */\n@serializable\nexport class TilemapComponent extends Component {\n readonly container: Container;\n readonly data: TilemapData;\n private readonly _tiledMap: TiledMapData;\n private readonly _mapKey: string | null;\n private readonly layerNames: string[] | undefined;\n private readonly renderLayerName: string;\n\n constructor(options: TilemapComponentOptions) {\n super();\n\n if (!options.map && !options.mapKey) {\n throw new Error(\n \"TilemapComponent requires either `map` or `mapKey`.\",\n );\n }\n\n this._mapKey = options.mapKey ?? null;\n const tiledMap = options.map ?? Assets.get<TiledMapData>(options.mapKey!);\n if (!tiledMap) {\n throw new Error(\n `TilemapComponent: map \"${options.mapKey}\" is not loaded. Add it to scene preload.`,\n );\n }\n\n this._tiledMap = tiledMap;\n this.data = toTilemapData(tiledMap);\n this.layerNames = options.layers;\n this.renderLayerName = options.layer ?? \"default\";\n this.container = new Container();\n }\n\n onAdd(): void {\n const tilemapLayers = createTilemapLayers(this._tiledMap, this.layerNames);\n for (const layer of tilemapLayers) {\n this.container.addChild(layer);\n }\n\n const renderLayer = this.use(SceneRenderTreeKey).get(this.renderLayerName);\n renderLayer.container.addChild(this.container);\n }\n\n onDestroy(): void {\n this.container.removeFromParent();\n this.container.destroy({ children: true });\n }\n\n serialize(): TilemapComponentData | null {\n if (!this._mapKey) {\n console.warn(\n `TilemapComponent on \"${this.entity?.name}\": created with a TiledMapData object. ` +\n `Use { mapKey } for save/load support.`,\n );\n return null;\n }\n return {\n mapKey: this._mapKey,\n layer: this.renderLayerName,\n ...(this.layerNames && { layers: this.layerNames }),\n };\n }\n\n static fromSnapshot(data: TilemapComponentData): TilemapComponent {\n return new TilemapComponent({\n mapKey: data.mapKey,\n layer: data.layer,\n ...(data.layers && { layers: data.layers }),\n });\n }\n\n /** Map width in pixels. */\n get widthPx(): number {\n return this.data.width * this.data.tileWidth;\n }\n\n /** Map height in pixels. */\n get heightPx(): number {\n return this.data.height * this.data.tileHeight;\n }\n\n /** Tile width in pixels. */\n get tileWidth(): number {\n return this.data.tileWidth;\n }\n\n /** Tile height in pixels. */\n get tileHeight(): number {\n return this.data.tileHeight;\n }\n\n /**\n * Returns the tile GID at a world position, accounting for entity Transform offset.\n * Returns null if the position is outside the map or the tile is empty.\n */\n getTileAt(\n worldX: number,\n worldY: number,\n layerName?: string,\n ): number | null {\n const transform = this.entity.tryGet(Transform);\n const offsetX = transform ? transform.position.x : 0;\n const offsetY = transform ? transform.position.y : 0;\n const localX = worldX - offsetX;\n const localY = worldY - offsetY;\n\n const col = Math.floor(localX / this.data.tileWidth);\n const row = Math.floor(localY / this.data.tileHeight);\n\n if (col < 0 || col >= this.data.width) return null;\n if (row < 0 || row >= this.data.height) return null;\n\n const layers = layerName\n ? this.data.tileLayers.filter((l) => l.name === layerName)\n : this.data.tileLayers;\n\n // Return first non-zero GID found (from last layer to first for top-most)\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i]!;\n const gid = layer.data[row * layer.width + col];\n if (gid !== undefined && gid !== 0) return gid;\n }\n\n return null;\n }\n\n /** Extract physics-agnostic collision shapes from object layers. */\n getCollisionShapes(objectLayerName?: string): TilemapColliderConfig[] {\n return extractCollisionShapes(this.data, objectLayerName);\n }\n\n /** Extract objects from object layers grouped by class/name. */\n getObjects(objectLayerName?: string): Record<string, MapObject[]> {\n const filtered = objectLayerName\n ? this.data.objectLayers.filter((l) => l.name === objectLayerName)\n : this.data.objectLayers;\n\n const result: Record<string, MapObject[]> = {};\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const key = obj.class ?? obj.name;\n if (!result[key]) {\n result[key] = [];\n }\n result[key].push(obj);\n }\n }\n\n return result;\n }\n}\n","import { CompositeTilemap } from \"@pixi/tilemap\";\nimport { Assets, Texture, Rectangle } from \"pixi.js\";\nimport type {\n TiledMapData,\n TileLayer,\n TilesetRef,\n ObjectGroup,\n TileObject,\n} from \"./types.js\";\nimport type {\n TilemapData,\n TileLayerData,\n ObjectLayerData,\n MapObject,\n} from \"../types.js\";\n\n// ─── Generic adapter ────────────────────────────────────────────────\n\n/**\n * Convert Tiled JSON data to the generic TilemapData format.\n */\nexport function toTilemapData(map: TiledMapData): TilemapData {\n const tileLayers: TileLayerData[] = [];\n const objectLayers: ObjectLayerData[] = [];\n\n for (const layer of map.layers) {\n if (layer.type === \"tilelayer\") {\n tileLayers.push({\n name: layer.name,\n data: layer.data,\n width: layer.width,\n height: layer.height,\n visible: layer.visible,\n });\n } else if (layer.type === \"objectgroup\") {\n objectLayers.push({\n name: layer.name,\n objects: layer.objects.map(tiledObjectToMapObject),\n visible: layer.visible,\n });\n }\n }\n\n return {\n width: map.width,\n height: map.height,\n tileWidth: map.tilewidth,\n tileHeight: map.tileheight,\n tileLayers,\n objectLayers,\n };\n}\n\nfunction tiledObjectToMapObject(obj: TileObject): MapObject {\n const result: MapObject = {\n id: obj.id,\n name: obj.name,\n x: obj.x,\n y: obj.y,\n width: obj.width,\n height: obj.height,\n rotation: obj.rotation,\n visible: obj.visible,\n };\n\n const cls = obj.class ?? obj.type;\n if (cls) result.class = cls;\n if (obj.point === true) result.point = true;\n if (obj.polygon) result.polygon = obj.polygon;\n if (obj.properties) {\n result.properties = obj.properties.map((p) => ({\n name: p.name,\n type: p.type,\n value: p.value,\n }));\n }\n\n return result;\n}\n\n// ─── Tiled-specific rendering ───────────────────────────────────────\n\n/**\n * Resolve the tileset that owns a given global tile ID.\n * Tilesets are sorted by firstgid; we find the last tileset whose firstgid <= gid.\n */\nfunction findTileset(tilesets: TilesetRef[], gid: number): TilesetRef | null {\n let result: TilesetRef | null = null;\n for (const ts of tilesets) {\n if (ts.firstgid <= gid) {\n if (!result || ts.firstgid > result.firstgid) {\n result = ts;\n }\n }\n }\n return result;\n}\n\n/**\n * Resolve the texture for a tile given its GID and owning tileset.\n */\nfunction resolveTileTexture(\n gid: number,\n tileset: TilesetRef,\n): Texture | null {\n const data = tileset.data;\n if (!data) return null;\n const localId = gid - tileset.firstgid;\n\n if (data.tiles?.length) {\n // Collection-of-images tileset: look up texture by filename from cache\n const tileData = data.tiles[localId];\n if (!tileData?.image) return null;\n const filenameMatch = tileData.image.match(/[^/]*$/);\n const filename = filenameMatch?.[0];\n if (!filename) return null;\n const tex = Assets.get<Texture>(filename);\n return tex ?? null;\n }\n\n if (data.image) {\n // Single-image tileset: sub-textures were created by the loader\n const cacheKey = `${data.name}:${localId}`;\n const tex = Assets.get<Texture>(cacheKey);\n if (tex) return tex;\n\n // Fallback: create sub-texture on the fly from the base image\n const filenameMatch = data.image.match(/[^/]*$/);\n const filename = filenameMatch?.[0];\n if (!filename) return null;\n const baseTex = Assets.get<Texture>(filename);\n if (!baseTex) return null;\n\n const cols = data.columns;\n const tw = data.tilewidth;\n const th = data.tileheight;\n const margin = data.margin ?? 0;\n const spacing = data.spacing ?? 0;\n const col = localId % cols;\n const row = Math.floor(localId / cols);\n const x = margin + col * (tw + spacing);\n const y = margin + row * (th + spacing);\n\n return new Texture({\n source: baseTex.source,\n frame: new Rectangle(x, y, tw, th),\n });\n }\n\n return null;\n}\n\n/**\n * Build CompositeTilemap display objects from a parsed Tiled map.\n *\n * @param map - Parsed TiledMapData (with resolved tilesets).\n * @param layerNames - Optional filter: only process these tile layer names.\n * @returns Array of CompositeTilemap, one per tile layer.\n */\nexport function createTilemapLayers(\n map: TiledMapData,\n layerNames?: string[],\n): CompositeTilemap[] {\n const tileLayers = map.layers.filter(\n (l): l is TileLayer => l.type === \"tilelayer\",\n );\n\n const filtered = layerNames\n ? tileLayers.filter((l) => layerNames.includes(l.name))\n : tileLayers;\n\n return filtered.map((layer) => {\n const tilemap = new CompositeTilemap();\n const { data, width } = layer;\n\n for (let index = 0; index < data.length; index++) {\n const gid = data[index]!;\n if (gid === 0) continue;\n\n const tileset = findTileset(map.tilesets, gid);\n if (!tileset) {\n throw new Error(`No tileset found for tile GID ${gid}`);\n }\n\n const texture = resolveTileTexture(gid, tileset);\n if (!texture) {\n throw new Error(\n `Could not resolve texture for tile GID ${gid} in tileset \"${tileset.data?.name}\"`,\n );\n }\n\n const x = index % width;\n const y = Math.floor(index / width);\n tilemap.tile(texture, x * map.tilewidth, y * map.tileheight);\n }\n\n return tilemap;\n });\n}\n\n/**\n * Extract objects from Tiled object layers, grouped by class/type/name.\n *\n * @param map - Parsed TiledMapData.\n * @param objectLayerName - Optional: only extract from this layer.\n * @returns Record mapping class/type/name to arrays of TileObject.\n */\nexport function extractObjects(\n map: TiledMapData,\n objectLayerName?: string,\n): Record<string, TileObject[]> {\n const objectLayers = map.layers.filter(\n (l): l is ObjectGroup => l.type === \"objectgroup\",\n );\n\n const filtered = objectLayerName\n ? objectLayers.filter((l) => l.name === objectLayerName)\n : objectLayers;\n\n const result: Record<string, TileObject[]> = {};\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const key = obj.class ?? obj.type ?? obj.name;\n if (!result[key]) {\n result[key] = [];\n }\n result[key].push(obj);\n }\n }\n\n return result;\n}\n","import type {\n TilemapData,\n MapObject,\n TilemapColliderConfig,\n RectColliderConfig,\n PolygonColliderConfig,\n} from \"./types.js\";\n\n/**\n * Extract physics-agnostic collision shapes from object layers.\n *\n * - Rectangle objects -> RectColliderConfig\n * - Polygon objects -> PolygonColliderConfig\n * - Point objects -> skipped (not collision shapes)\n *\n * @param map - Generic TilemapData.\n * @param objectLayerName - Optional: only extract from this layer.\n */\nexport function extractCollisionShapes(\n map: TilemapData,\n objectLayerName?: string,\n): TilemapColliderConfig[] {\n const filtered = objectLayerName\n ? map.objectLayers.filter((l) => l.name === objectLayerName)\n : map.objectLayers;\n\n const shapes: TilemapColliderConfig[] = [];\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const shape = objectToColliderConfig(obj);\n if (shape) shapes.push(shape);\n }\n }\n\n return shapes;\n}\n\n/**\n * Convert a single MapObject to a ColliderConfig.\n * Returns null for point objects (not collision shapes).\n */\nfunction objectToColliderConfig(obj: MapObject): TilemapColliderConfig | null {\n // Skip point objects\n if (obj.point) return null;\n\n if (obj.polygon) {\n const config: PolygonColliderConfig = {\n type: \"polygon\",\n x: obj.x,\n y: obj.y,\n vertices: obj.polygon.map((v) => ({ x: v.x, y: v.y })),\n };\n return config;\n }\n\n // Rectangle object\n const config: RectColliderConfig = {\n type: \"rect\",\n x: obj.x,\n y: obj.y,\n width: obj.width,\n height: obj.height,\n };\n return config;\n}\n","import { AssetHandle } from \"@yagejs/core\";\nimport type { TiledMapData } from \"./tiled/types.js\";\n\n/** Create a typed asset handle for a Tiled map JSON. */\nexport function tiledMap(path: string): AssetHandle<TiledMapData> {\n return new AssetHandle(\"tiledMap\", path);\n}\n","import type { ColliderConfig as PhysicsColliderConfig } from \"@yagejs/physics\";\nimport type { TilemapColliderConfig } from \"./types.js\";\n\n/**\n * Convert tilemap TilemapColliderConfig[] (top-left origin rects/polygons) into\n * physics-package ColliderConfig[] (center-origin shape + offset).\n */\nexport function toPhysicsColliders(\n shapes: TilemapColliderConfig[],\n): PhysicsColliderConfig[] {\n return shapes.map(toPhysicsCollider);\n}\n\nfunction toPhysicsCollider(config: TilemapColliderConfig): PhysicsColliderConfig {\n switch (config.type) {\n case \"polygon\":\n return {\n shape: {\n type: \"polygon\",\n vertices: config.vertices,\n },\n offset: { x: config.x, y: config.y },\n };\n case \"rect\":\n return {\n shape: { type: \"box\", width: config.width, height: config.height },\n offset: {\n x: config.x + config.width / 2,\n y: config.y + config.height / 2,\n },\n };\n }\n}\n","import type { HasProperties, MapObject } from \"./types.js\";\n\n/**\n * Get a single property value by name.\n * Returns `undefined` if the property is not found.\n */\nexport function getProperty<T = unknown>(\n obj: HasProperties,\n name: string,\n): T | undefined {\n const prop = obj.properties?.find((p) => p.name === name);\n return prop?.value as T | undefined;\n}\n\n/**\n * Get a pseudo-array of property values.\n *\n * Tiled doesn't support array properties natively, so a common convention\n * is to use indexed names like `spawns[0]`, `spawns[1]`, etc.\n * This function collects them into a proper array, preserving index order.\n */\nexport function getPropertyArray<T = unknown>(\n obj: HasProperties,\n name: string,\n): T[] {\n const pattern = new RegExp(`^${escapeRegex(name)}\\\\[(\\\\d+)\\\\]$`);\n const values: T[] = [];\n\n if (!obj.properties) return values;\n\n for (const prop of obj.properties) {\n const match = prop.name.match(pattern);\n if (match) {\n const index = Number.parseInt(match[1]!, 10);\n values[index] = prop.value as T;\n }\n }\n\n return values;\n}\n\n/**\n * Resolve a property of `type: \"object\"` (an ID reference) to the actual MapObject.\n * Returns `undefined` if the property doesn't exist or the referenced object isn't found.\n */\nexport function resolveObjectRef(\n obj: HasProperties,\n propName: string,\n allObjects: MapObject[],\n): MapObject | undefined {\n const id = getProperty<number>(obj, propName);\n if (id === undefined) return undefined;\n return allObjects.find((o) => o.id === id);\n}\n\n/**\n * Resolve a pseudo-array of object ID references to actual MapObjects.\n * Uses the `name[0]`, `name[1]` convention.\n */\nexport function resolveObjectRefArray(\n obj: HasProperties,\n propName: string,\n allObjects: MapObject[],\n): MapObject[] {\n const ids = getPropertyArray<number>(obj, propName);\n return ids\n .map((id) => allObjects.find((o) => o.id === id))\n .filter((o): o is MapObject => o !== undefined);\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n"],"mappings":"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","names":["Assets","Transform","Assets","Assets","Texture","Rectangle","Assets","Texture","Rectangle","config","tiledMap","Assets","Transform","path","Assets","path"]}
1
+ {"version":3,"sources":["../src/TilemapPlugin.ts","../src/tiled/tiledMapLoader.ts","../src/TilemapRenderSystem.ts","../src/TilemapComponent.ts","../src/tiled/parseTiledMap.ts","../src/colliders.ts","../src/keys.ts","../src/properties.ts","../src/assets.ts","../src/toPhysicsColliders.ts"],"sourcesContent":["import { AssetManagerKey } from \"@yagejs/core\";\nimport type { EngineContext, Plugin, SystemScheduler } from \"@yagejs/core\";\nimport { extensions, Assets } from \"pixi.js\";\nimport { tiledMapAssetExtension } from \"./tiled/tiledMapLoader.js\";\nimport { TilemapRenderSystem } from \"./TilemapRenderSystem.js\";\nimport type { TiledMapData } from \"./tiled/types.js\";\n\n/** Plugin that adds Tiled map loading and rendering to YAGE. */\nexport class TilemapPlugin implements Plugin {\n readonly name = \"tilemap\";\n readonly version = \"2.0.0\";\n readonly dependencies = [\"renderer\"] as const;\n\n install(context: EngineContext): void {\n // Register PixiJS loader extension for Tiled map JSON files\n extensions.add(tiledMapAssetExtension);\n\n // Register \"tiledMap\" loader with AssetManager\n const am = context.tryResolve(AssetManagerKey);\n am?.registerLoader(\"tiledMap\", {\n load: (path: string) => Assets.load<TiledMapData>(path),\n unload: (path: string) => {\n Assets.unload(path);\n },\n });\n }\n\n registerSystems(scheduler: SystemScheduler): void {\n scheduler.add(new TilemapRenderSystem());\n }\n}\n","import {\n ExtensionType,\n LoaderParserPriority,\n Assets,\n path,\n Texture,\n Rectangle,\n} from \"pixi.js\";\nimport type { LoaderParser, ResolvedAsset, Loader } from \"pixi.js\";\nimport type { TiledMapData, TilesetData, TilesetRef } from \"./types.js\";\n\n/**\n * PixiJS loader extension that detects Tiled map JSON files and resolves\n * their tileset references.\n *\n * Supports two tileset formats:\n * 1. **Collection-of-images** — tileset has `tiles[]` with image paths.\n * Assumes textures are already in the PixiJS cache (e.g. from a\n * pre-loaded spritesheet atlas).\n * 2. **Single-image tileset** — tileset has an `image` property pointing\n * to a spritesheet. The loader loads the image and creates sub-textures\n * for each tile based on grid layout.\n */\nconst tiledMapLoaderParser: LoaderParser<TiledMapData> = {\n id: \"tiledMapLoader\",\n\n extension: {\n type: ExtensionType.LoadParser,\n priority: LoaderParserPriority.High,\n },\n\n async testParse(\n asset: TiledMapData,\n resolvedAsset?: ResolvedAsset,\n ): Promise<boolean> {\n if (!resolvedAsset?.src) return false;\n if (path.extname(resolvedAsset.src).toLowerCase() !== \".json\") return false;\n const obj = asset as unknown as Record<string, unknown>;\n return !!(obj.tilesets && obj.layers);\n },\n\n async parse(\n asset: TiledMapData,\n resolvedAsset?: ResolvedAsset,\n loader?: Loader,\n ): Promise<TiledMapData> {\n const src = resolvedAsset?.src;\n if (!src || !loader) return asset;\n\n let basePath = path.dirname(src);\n if (basePath && !basePath.endsWith(\"/\")) {\n basePath += \"/\";\n }\n\n for (const tilesetRef of asset.tilesets as TilesetRef[]) {\n if (tilesetRef.source) {\n // External tileset JSON — load it\n const tilesetPath = basePath + tilesetRef.source;\n const tilesetData = (await loader.load<TilesetData>({\n src: tilesetPath,\n })) as TilesetData;\n tilesetRef.data = tilesetData;\n }\n\n const tileset = tilesetRef.data;\n if (!tileset) continue;\n\n // Single-image tileset: load the image and create sub-textures\n if (tileset.image && !tileset.tiles?.length) {\n const imagePath = basePath + tileset.image;\n const baseTexture = await Assets.load<Texture>(imagePath);\n const cols = tileset.columns;\n const tw = tileset.tilewidth;\n const th = tileset.tileheight;\n const margin = tileset.margin ?? 0;\n const spacing = tileset.spacing ?? 0;\n\n for (let id = 0; id < tileset.tilecount; id++) {\n const col = id % cols;\n const row = Math.floor(id / cols);\n const x = margin + col * (tw + spacing);\n const y = margin + row * (th + spacing);\n\n const frame = new Rectangle(x, y, tw, th);\n const subtex = new Texture({\n source: baseTexture.source,\n frame,\n });\n\n // Store subtexture in PixiJS cache with a key like \"tileset-name:id\"\n const cacheKey = `${tileset.name}:${id}`;\n Assets.cache.set(cacheKey, subtex);\n }\n }\n // Collection-of-images: textures are expected to already be\n // in the PixiJS cache (loaded via spritesheet atlas).\n }\n\n return asset;\n },\n\n unload() {},\n};\n\n/** PixiJS asset extension bundle for Tiled map JSON files. */\nexport const tiledMapAssetExtension = {\n extension: ExtensionType.Asset,\n loader: tiledMapLoaderParser,\n};\n","import { System, Phase, Transform, QueryCacheKey } from \"@yagejs/core\";\nimport type { EngineContext, QueryResult } from \"@yagejs/core\";\nimport { TilemapComponent } from \"./TilemapComponent.js\";\n\n/** Syncs Transform to TilemapComponent display containers. */\nexport class TilemapRenderSystem extends System {\n readonly phase = Phase.Render;\n readonly priority = -1; // Before DisplaySystem (0), so tilemaps render behind sprites\n\n private query!: QueryResult;\n\n onRegister(context: EngineContext): void {\n const queryCache = context.resolve(QueryCacheKey);\n this.query = queryCache.register([Transform, TilemapComponent]);\n }\n\n update(): void {\n for (const entity of this.query) {\n const transform = entity.get(Transform);\n const tilemap = entity.get(TilemapComponent);\n if (!tilemap.enabled) continue;\n\n tilemap.container.position.x = transform.worldPosition.x;\n tilemap.container.position.y = transform.worldPosition.y;\n tilemap.container.rotation = transform.worldRotation;\n tilemap.container.scale.x = transform.worldScale.x;\n tilemap.container.scale.y = transform.worldScale.y;\n }\n }\n}\n","import { Component, Transform, serializable } from \"@yagejs/core\";\nimport type { AssetHandle } from \"@yagejs/core\";\nimport { Assets, Container } from \"pixi.js\";\nimport { SceneRenderTreeKey } from \"@yagejs/renderer\";\nimport { createTilemapLayers, toTilemapData } from \"./tiled/parseTiledMap.js\";\nimport { extractCollisionShapes } from \"./colliders.js\";\nimport { tiledObjectKey } from \"./keys.js\";\nimport {\n getProperty,\n getPropertyArray,\n resolveObjectRef,\n resolveObjectRefArray,\n} from \"./properties.js\";\nimport type { TiledMapData } from \"./tiled/types.js\";\nimport type {\n TilemapData,\n MapObject,\n TilemapColliderConfig,\n} from \"./types.js\";\n\n/** Options for creating a TilemapComponent. */\nexport interface TilemapComponentOptions {\n /** Asset handle for the map. Preferred — captures both the parsed data and the asset path. */\n source?: AssetHandle<TiledMapData>;\n /** Parsed Tiled map data. Use only when you don't have an AssetHandle. Save/load and auto-keys require `mapKey` or `source`. */\n map?: TiledMapData;\n /** Asset path to the Tiled JSON. Resolved via `Assets.get`. Save/load uses this. */\n mapKey?: string;\n /** Which tile layers to render. Omit to render all. */\n layers?: string[];\n /** Render layer name. Default: \"default\". */\n layer?: string;\n /**\n * Override prefix used when auto-keying entities spawned from Tiled objects.\n * Defaults to `mapKey`. Set this when multiple instances of the same map need\n * distinct entity-key namespaces (e.g. instanced dungeons).\n */\n keyPrefix?: string;\n}\n\n/** Serializable snapshot of a TilemapComponent. */\nexport interface TilemapComponentData {\n mapKey: string;\n layers?: string[];\n layer: string;\n keyPrefix?: string;\n}\n\n/** Component that renders a Tiled map using @pixi/tilemap. */\n@serializable\nexport class TilemapComponent extends Component {\n readonly container: Container;\n readonly data: TilemapData;\n /** Asset path of this map, or `null` if constructed from a raw `TiledMapData` without one. */\n readonly mapKey: string | null;\n /** Prefix used to derive auto-keys for entities spawned from objects. */\n readonly keyPrefix: string | null;\n private readonly _tiledMap: TiledMapData;\n private readonly layerNames: string[] | undefined;\n private readonly renderLayerName: string;\n private readonly _explicitKeyPrefix: string | undefined;\n /** Lazy flat-list cache. The parsed map is treated as immutable post-construction; if that ever changes, callers must invalidate. */\n private _allObjectsCache: MapObject[] | undefined;\n\n constructor(options: TilemapComponentOptions) {\n super();\n\n const sourceCount =\n (options.source ? 1 : 0) +\n (options.map ? 1 : 0) +\n (options.mapKey ? 1 : 0);\n if (sourceCount === 0) {\n throw new Error(\n \"TilemapComponent requires one of `source`, `map`, or `mapKey`.\",\n );\n }\n\n if (options.source) {\n this.mapKey = options.source.path;\n const data = Assets.get<TiledMapData>(options.source.path);\n if (!data) {\n throw new Error(\n `TilemapComponent: source \"${options.source.path}\" is not loaded. Add it to scene preload.`,\n );\n }\n this._tiledMap = data;\n } else if (options.mapKey) {\n this.mapKey = options.mapKey;\n const data = Assets.get<TiledMapData>(options.mapKey);\n if (!data) {\n throw new Error(\n `TilemapComponent: map \"${options.mapKey}\" is not loaded. Add it to scene preload.`,\n );\n }\n this._tiledMap = data;\n } else {\n this.mapKey = null;\n this._tiledMap = options.map!;\n }\n\n this.data = toTilemapData(this._tiledMap);\n this.layerNames = options.layers;\n this.renderLayerName = options.layer ?? \"default\";\n this._explicitKeyPrefix = options.keyPrefix;\n this.keyPrefix = options.keyPrefix ?? this.mapKey;\n this.container = new Container();\n }\n\n onAdd(): void {\n const tilemapLayers = createTilemapLayers(this._tiledMap, this.layerNames);\n for (const layer of tilemapLayers) {\n this.container.addChild(layer);\n }\n\n const renderLayer = this.use(SceneRenderTreeKey).get(this.renderLayerName);\n renderLayer.container.addChild(this.container);\n }\n\n onDestroy(): void {\n this.container.removeFromParent();\n this.container.destroy({ children: true });\n }\n\n serialize(): TilemapComponentData | null {\n if (!this.mapKey) {\n console.warn(\n `TilemapComponent on \"${this.entity?.name}\": created with a TiledMapData object. ` +\n `Use { source } or { mapKey } for save/load support.`,\n );\n return null;\n }\n return {\n mapKey: this.mapKey,\n layer: this.renderLayerName,\n ...(this.layerNames && { layers: this.layerNames }),\n ...(this._explicitKeyPrefix !== undefined && {\n keyPrefix: this._explicitKeyPrefix,\n }),\n };\n }\n\n static fromSnapshot(data: TilemapComponentData): TilemapComponent {\n return new TilemapComponent({\n mapKey: data.mapKey,\n layer: data.layer,\n ...(data.layers && { layers: data.layers }),\n ...(data.keyPrefix !== undefined && { keyPrefix: data.keyPrefix }),\n });\n }\n\n /** Map width in pixels. */\n get widthPx(): number {\n return this.data.width * this.data.tileWidth;\n }\n\n /** Map height in pixels. */\n get heightPx(): number {\n return this.data.height * this.data.tileHeight;\n }\n\n /** Tile width in pixels. */\n get tileWidth(): number {\n return this.data.tileWidth;\n }\n\n /** Tile height in pixels. */\n get tileHeight(): number {\n return this.data.tileHeight;\n }\n\n /**\n * Returns the tile GID at a world position, accounting for entity Transform offset.\n * Returns null if the position is outside the map or the tile is empty.\n */\n getTileAt(\n worldX: number,\n worldY: number,\n layerName?: string,\n ): number | null {\n const transform = this.entity.tryGet(Transform);\n const offsetX = transform ? transform.position.x : 0;\n const offsetY = transform ? transform.position.y : 0;\n const localX = worldX - offsetX;\n const localY = worldY - offsetY;\n\n const col = Math.floor(localX / this.data.tileWidth);\n const row = Math.floor(localY / this.data.tileHeight);\n\n if (col < 0 || col >= this.data.width) return null;\n if (row < 0 || row >= this.data.height) return null;\n\n const layers = layerName\n ? this.data.tileLayers.filter((l) => l.name === layerName)\n : this.data.tileLayers;\n\n // Return first non-zero GID found (from last layer to first for top-most)\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i]!;\n const gid = layer.data[row * layer.width + col];\n if (gid !== undefined && gid !== 0) return gid;\n }\n\n return null;\n }\n\n /** Extract physics-agnostic collision shapes from object layers. */\n getCollisionShapes(objectLayerName?: string): TilemapColliderConfig[] {\n return extractCollisionShapes(this.data, objectLayerName);\n }\n\n /** Objects from object layers grouped by `class ?? name`. Use a layer name to scope. */\n getObjects(objectLayerName?: string): Record<string, MapObject[]> {\n const filtered = objectLayerName\n ? this.data.objectLayers.filter((l) => l.name === objectLayerName)\n : this.data.objectLayers;\n\n const result: Record<string, MapObject[]> = {};\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const key = obj.class ?? obj.name;\n if (!result[key]) {\n result[key] = [];\n }\n result[key].push(obj);\n }\n }\n\n return result;\n }\n\n /** Flat list of every object across every object layer. Memoized — safe because parsed map data is immutable post-construction. */\n getAllObjects(): MapObject[] {\n if (this._allObjectsCache) return this._allObjectsCache;\n const result: MapObject[] = [];\n for (const layer of this.data.objectLayers) {\n for (const obj of layer.objects) result.push(obj);\n }\n this._allObjectsCache = result;\n return result;\n }\n\n /**\n * Iterate every object on the given layer (or every layer if omitted),\n * passing the auto-derived stable key alongside each object so callers can\n * spawn entities with `scene.spawn(Class, params, { key })`.\n *\n * Skips objects that don't have a key prefix (component constructed from raw\n * `map:` without `mapKey` or `keyPrefix`) — those callers should iterate\n * `getObjects` directly.\n */\n forEachObject(\n layerName: string | undefined,\n fn: (obj: MapObject, key: string) => void,\n ): void {\n if (this.keyPrefix === null) {\n throw new Error(\n \"TilemapComponent.forEachObject: cannot derive auto-keys without a `mapKey`, `source`, or explicit `keyPrefix`.\",\n );\n }\n const layers = layerName\n ? this.data.objectLayers.filter((l) => l.name === layerName)\n : this.data.objectLayers;\n for (const layer of layers) {\n for (const obj of layer.objects) {\n fn(obj, tiledObjectKey(this.keyPrefix, obj.id));\n }\n }\n }\n\n /** Auto-derived stable key for an object: `<keyPrefix>#object:<id>`. */\n objectKey(obj: MapObject): string {\n if (this.keyPrefix === null) {\n throw new Error(\n \"TilemapComponent.objectKey: cannot derive a key without a `mapKey`, `source`, or explicit `keyPrefix`.\",\n );\n }\n return tiledObjectKey(this.keyPrefix, obj.id);\n }\n\n /** Find an object by its Tiled `id`. Searches every object layer. */\n findObject(id: number): MapObject | undefined {\n for (const layer of this.data.objectLayers) {\n for (const obj of layer.objects) {\n if (obj.id === id) return obj;\n }\n }\n return undefined;\n }\n\n /** Find the first object with a matching `name`. Searches every object layer. */\n findObjectByName(name: string): MapObject | undefined {\n for (const layer of this.data.objectLayers) {\n for (const obj of layer.objects) {\n if (obj.name === name) return obj;\n }\n }\n return undefined;\n }\n\n /** Read a typed custom property off any tilemap object. */\n getProperty<T = unknown>(obj: MapObject, name: string): T | undefined {\n return getProperty<T>(obj, name);\n }\n\n /** Read an indexed property bag (`name[0]`, `name[1]`, ...) as an array. */\n getPropertyArray<T = unknown>(obj: MapObject, name: string): T[] {\n return getPropertyArray<T>(obj, name);\n }\n\n /**\n * Resolve a Tiled object-reference property to the actual object.\n * Auto-collects across every layer so callers don't have to.\n */\n resolveRef(obj: MapObject, propName: string): MapObject | undefined {\n return resolveObjectRef(obj, propName, this.getAllObjects());\n }\n\n /** Same as `resolveRef`, but for indexed object-reference arrays. */\n resolveRefArray(obj: MapObject, propName: string): MapObject[] {\n return resolveObjectRefArray(obj, propName, this.getAllObjects());\n }\n}\n","import { CompositeTilemap } from \"@pixi/tilemap\";\nimport { Assets, Texture, Rectangle } from \"pixi.js\";\nimport type {\n TiledMapData,\n TileLayer,\n TilesetRef,\n ObjectGroup,\n TileObject,\n} from \"./types.js\";\nimport type {\n TilemapData,\n TileLayerData,\n ObjectLayerData,\n MapObject,\n} from \"../types.js\";\n\n// ─── Generic adapter ────────────────────────────────────────────────\n\n/**\n * Convert Tiled JSON data to the generic TilemapData format.\n */\nexport function toTilemapData(map: TiledMapData): TilemapData {\n const tileLayers: TileLayerData[] = [];\n const objectLayers: ObjectLayerData[] = [];\n\n for (const layer of map.layers) {\n if (layer.type === \"tilelayer\") {\n tileLayers.push({\n name: layer.name,\n data: layer.data,\n width: layer.width,\n height: layer.height,\n visible: layer.visible,\n });\n } else if (layer.type === \"objectgroup\") {\n objectLayers.push({\n name: layer.name,\n objects: layer.objects.map(tiledObjectToMapObject),\n visible: layer.visible,\n });\n }\n }\n\n return {\n width: map.width,\n height: map.height,\n tileWidth: map.tilewidth,\n tileHeight: map.tileheight,\n tileLayers,\n objectLayers,\n };\n}\n\nfunction tiledObjectToMapObject(obj: TileObject): MapObject {\n const result: MapObject = {\n id: obj.id,\n name: obj.name,\n x: obj.x,\n y: obj.y,\n width: obj.width,\n height: obj.height,\n rotation: obj.rotation,\n visible: obj.visible,\n };\n\n const cls = obj.class ?? obj.type;\n if (cls) result.class = cls;\n if (obj.point === true) result.point = true;\n if (obj.polygon) result.polygon = obj.polygon;\n if (obj.properties) {\n result.properties = obj.properties.map((p) => ({\n name: p.name,\n type: p.type,\n value: p.value,\n }));\n }\n\n return result;\n}\n\n// ─── Tiled-specific rendering ───────────────────────────────────────\n\n/**\n * Resolve the tileset that owns a given global tile ID.\n * Tilesets are sorted by firstgid; we find the last tileset whose firstgid <= gid.\n */\nfunction findTileset(tilesets: TilesetRef[], gid: number): TilesetRef | null {\n let result: TilesetRef | null = null;\n for (const ts of tilesets) {\n if (ts.firstgid <= gid) {\n if (!result || ts.firstgid > result.firstgid) {\n result = ts;\n }\n }\n }\n return result;\n}\n\n/**\n * Resolve the texture for a tile given its GID and owning tileset.\n */\nfunction resolveTileTexture(\n gid: number,\n tileset: TilesetRef,\n): Texture | null {\n const data = tileset.data;\n if (!data) return null;\n const localId = gid - tileset.firstgid;\n\n if (data.tiles?.length) {\n // Collection-of-images tileset: look up texture by filename from cache\n const tileData = data.tiles[localId];\n if (!tileData?.image) return null;\n const filenameMatch = tileData.image.match(/[^/]*$/);\n const filename = filenameMatch?.[0];\n if (!filename) return null;\n const tex = Assets.get<Texture>(filename);\n return tex ?? null;\n }\n\n if (data.image) {\n // Single-image tileset: sub-textures were created by the loader\n const cacheKey = `${data.name}:${localId}`;\n const tex = Assets.get<Texture>(cacheKey);\n if (tex) return tex;\n\n // Fallback: create sub-texture on the fly from the base image\n const filenameMatch = data.image.match(/[^/]*$/);\n const filename = filenameMatch?.[0];\n if (!filename) return null;\n const baseTex = Assets.get<Texture>(filename);\n if (!baseTex) return null;\n\n const cols = data.columns;\n const tw = data.tilewidth;\n const th = data.tileheight;\n const margin = data.margin ?? 0;\n const spacing = data.spacing ?? 0;\n const col = localId % cols;\n const row = Math.floor(localId / cols);\n const x = margin + col * (tw + spacing);\n const y = margin + row * (th + spacing);\n\n return new Texture({\n source: baseTex.source,\n frame: new Rectangle(x, y, tw, th),\n });\n }\n\n return null;\n}\n\n/**\n * Build CompositeTilemap display objects from a parsed Tiled map.\n *\n * @param map - Parsed TiledMapData (with resolved tilesets).\n * @param layerNames - Optional filter: only process these tile layer names.\n * @returns Array of CompositeTilemap, one per tile layer.\n */\nexport function createTilemapLayers(\n map: TiledMapData,\n layerNames?: string[],\n): CompositeTilemap[] {\n const tileLayers = map.layers.filter(\n (l): l is TileLayer => l.type === \"tilelayer\",\n );\n\n const filtered = layerNames\n ? tileLayers.filter((l) => layerNames.includes(l.name))\n : tileLayers;\n\n return filtered.map((layer) => {\n const tilemap = new CompositeTilemap();\n const { data, width } = layer;\n\n for (let index = 0; index < data.length; index++) {\n const gid = data[index]!;\n if (gid === 0) continue;\n\n const tileset = findTileset(map.tilesets, gid);\n if (!tileset) {\n throw new Error(`No tileset found for tile GID ${gid}`);\n }\n\n const texture = resolveTileTexture(gid, tileset);\n if (!texture) {\n throw new Error(\n `Could not resolve texture for tile GID ${gid} in tileset \"${tileset.data?.name}\"`,\n );\n }\n\n const x = index % width;\n const y = Math.floor(index / width);\n tilemap.tile(texture, x * map.tilewidth, y * map.tileheight);\n }\n\n return tilemap;\n });\n}\n\n/**\n * Extract objects from Tiled object layers, grouped by class/type/name.\n *\n * @param map - Parsed TiledMapData.\n * @param objectLayerName - Optional: only extract from this layer.\n * @returns Record mapping class/type/name to arrays of TileObject.\n */\nexport function extractObjects(\n map: TiledMapData,\n objectLayerName?: string,\n): Record<string, TileObject[]> {\n const objectLayers = map.layers.filter(\n (l): l is ObjectGroup => l.type === \"objectgroup\",\n );\n\n const filtered = objectLayerName\n ? objectLayers.filter((l) => l.name === objectLayerName)\n : objectLayers;\n\n const result: Record<string, TileObject[]> = {};\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const key = obj.class ?? obj.type ?? obj.name;\n if (!result[key]) {\n result[key] = [];\n }\n result[key].push(obj);\n }\n }\n\n return result;\n}\n","import type {\n TilemapData,\n MapObject,\n TilemapColliderConfig,\n RectColliderConfig,\n PolygonColliderConfig,\n} from \"./types.js\";\n\n/**\n * Extract physics-agnostic collision shapes from object layers.\n *\n * - Rectangle objects -> RectColliderConfig\n * - Polygon objects -> PolygonColliderConfig\n * - Point objects -> skipped (not collision shapes)\n *\n * @param map - Generic TilemapData.\n * @param objectLayerName - Optional: only extract from this layer.\n */\nexport function extractCollisionShapes(\n map: TilemapData,\n objectLayerName?: string,\n): TilemapColliderConfig[] {\n const filtered = objectLayerName\n ? map.objectLayers.filter((l) => l.name === objectLayerName)\n : map.objectLayers;\n\n const shapes: TilemapColliderConfig[] = [];\n\n for (const layer of filtered) {\n for (const obj of layer.objects) {\n const shape = objectToColliderConfig(obj);\n if (shape) shapes.push(shape);\n }\n }\n\n return shapes;\n}\n\n/**\n * Convert a single MapObject to a ColliderConfig.\n * Returns null for point objects (not collision shapes).\n */\nfunction objectToColliderConfig(obj: MapObject): TilemapColliderConfig | null {\n // Skip point objects\n if (obj.point) return null;\n\n if (obj.polygon) {\n const config: PolygonColliderConfig = {\n type: \"polygon\",\n x: obj.x,\n y: obj.y,\n vertices: obj.polygon.map((v) => ({ x: v.x, y: v.y })),\n };\n return config;\n }\n\n // Rectangle object\n const config: RectColliderConfig = {\n type: \"rect\",\n x: obj.x,\n y: obj.y,\n width: obj.width,\n height: obj.height,\n };\n return config;\n}\n","/**\n * Build the stable identity key for an entity sourced from a Tiled object.\n *\n * Format: `<prefix>#object:<id>`. The prefix is normally the map's asset path\n * (e.g. `/assets/dungeon/dungeon-map.json#object:42`); pass an explicit prefix\n * when distinguishing between multiple instances of the same map.\n *\n * Use this to thread Tiled object identity into `scene.spawn(Class, params, { key })`\n * so persistent stores (`defineSet<string>`, `defineMap<string, T>`) can key off\n * authored level content without each game inventing its own naming scheme.\n */\nexport function tiledObjectKey(prefix: string, objectId: number): string {\n return `${prefix}#object:${objectId}`;\n}\n","import type { HasProperties, MapObject } from \"./types.js\";\n\n/**\n * Get a single property value by name.\n * Returns `undefined` if the property is not found.\n */\nexport function getProperty<T = unknown>(\n obj: HasProperties,\n name: string,\n): T | undefined {\n const prop = obj.properties?.find((p) => p.name === name);\n return prop?.value as T | undefined;\n}\n\n/**\n * Get a pseudo-array of property values.\n *\n * Tiled doesn't support array properties natively, so a common convention\n * is to use indexed names like `spawns[0]`, `spawns[1]`, etc.\n * This function collects them into a proper array, preserving index order.\n */\nexport function getPropertyArray<T = unknown>(\n obj: HasProperties,\n name: string,\n): T[] {\n const pattern = new RegExp(`^${escapeRegex(name)}\\\\[(\\\\d+)\\\\]$`);\n const values: T[] = [];\n\n if (!obj.properties) return values;\n\n for (const prop of obj.properties) {\n const match = prop.name.match(pattern);\n if (match) {\n const index = Number.parseInt(match[1]!, 10);\n values[index] = prop.value as T;\n }\n }\n\n return values;\n}\n\n/**\n * Resolve a property of `type: \"object\"` (an ID reference) to the actual MapObject.\n * Returns `undefined` if the property doesn't exist or the referenced object isn't found.\n */\nexport function resolveObjectRef(\n obj: HasProperties,\n propName: string,\n allObjects: MapObject[],\n): MapObject | undefined {\n const id = getProperty<number>(obj, propName);\n if (id === undefined) return undefined;\n return allObjects.find((o) => o.id === id);\n}\n\n/**\n * Resolve a pseudo-array of object ID references to actual MapObjects.\n * Uses the `name[0]`, `name[1]` convention.\n */\nexport function resolveObjectRefArray(\n obj: HasProperties,\n propName: string,\n allObjects: MapObject[],\n): MapObject[] {\n const ids = getPropertyArray<number>(obj, propName);\n return ids\n .map((id) => allObjects.find((o) => o.id === id))\n .filter((o): o is MapObject => o !== undefined);\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","import { AssetHandle } from \"@yagejs/core\";\nimport type { TiledMapData } from \"./tiled/types.js\";\n\n/** Create a typed asset handle for a Tiled map JSON. */\nexport function tiledMap(path: string): AssetHandle<TiledMapData> {\n return new AssetHandle(\"tiledMap\", path);\n}\n","import type { ColliderConfig as PhysicsColliderConfig } from \"@yagejs/physics\";\nimport type { TilemapColliderConfig } from \"./types.js\";\n\n/**\n * Convert tilemap TilemapColliderConfig[] (top-left origin rects/polygons) into\n * physics-package ColliderConfig[] (center-origin shape + offset).\n */\nexport function toPhysicsColliders(\n shapes: TilemapColliderConfig[],\n): PhysicsColliderConfig[] {\n return shapes.map(toPhysicsCollider);\n}\n\nfunction toPhysicsCollider(config: TilemapColliderConfig): PhysicsColliderConfig {\n switch (config.type) {\n case \"polygon\":\n return {\n shape: {\n type: \"polygon\",\n vertices: config.vertices,\n },\n offset: { x: config.x, y: config.y },\n };\n case \"rect\":\n return {\n shape: { type: \"box\", width: config.width, height: config.height },\n offset: {\n x: config.x + config.width / 2,\n y: config.y + config.height / 2,\n },\n };\n }\n}\n"],"mappings":"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","names":["Assets","Transform","Assets","Assets","Texture","Rectangle","Assets","Texture","Rectangle","config","Assets","Transform","path","Assets","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yagejs/tilemap",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Tile-based map loading and rendering for YAGE",
5
5
  "keywords": [
6
6
  "yage",
@@ -48,12 +48,12 @@
48
48
  "clean": "rm -rf dist"
49
49
  },
50
50
  "dependencies": {
51
- "@yagejs/core": "^0.4.0",
52
- "@yagejs/renderer": "^0.4.0",
51
+ "@yagejs/core": "^0.6.0",
52
+ "@yagejs/renderer": "^0.6.0",
53
53
  "@pixi/tilemap": "^5.0.0",
54
54
  "pixi.js": "^8.5.0"
55
55
  },
56
56
  "devDependencies": {
57
- "@yagejs/physics": "^0.4.0"
57
+ "@yagejs/physics": "^0.6.0"
58
58
  }
59
59
  }