@yagejs/tilemap 0.1.0 → 0.2.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
@@ -388,8 +388,7 @@ var _TilemapComponent = class _TilemapComponent extends (_a = import_core.Compon
388
388
  for (const layer of tilemapLayers) {
389
389
  this.container.addChild(layer);
390
390
  }
391
- const layers = this.use(import_renderer.RenderLayerManagerKey);
392
- const renderLayer = layers.get(this.renderLayerName);
391
+ const renderLayer = this.use(import_renderer.SceneRenderTreeKey).get(this.renderLayerName);
393
392
  renderLayer.container.addChild(this.container);
394
393
  }
395
394
  onDestroy() {
@@ -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 { RenderLayerManagerKey } 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 layers = this.use(RenderLayerManagerKey);\n const renderLayer = layers.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":["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/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":"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","names":["import_core","import_pixi","import_core","import_pixi","import_pixi","config","tiledMap","path","import_core","path"]}
package/dist/index.js CHANGED
@@ -127,7 +127,7 @@ import { System, Phase, Transform as Transform2, QueryCacheKey } from "@yagejs/c
127
127
  // src/TilemapComponent.ts
128
128
  import { Component, Transform, serializable } from "@yagejs/core";
129
129
  import { Assets as Assets3, Container } from "pixi.js";
130
- import { RenderLayerManagerKey } from "@yagejs/renderer";
130
+ import { SceneRenderTreeKey } from "@yagejs/renderer";
131
131
 
132
132
  // src/tiled/parseTiledMap.ts
133
133
  import { CompositeTilemap } from "@pixi/tilemap";
@@ -359,8 +359,7 @@ var _TilemapComponent = class _TilemapComponent extends (_a = Component) {
359
359
  for (const layer of tilemapLayers) {
360
360
  this.container.addChild(layer);
361
361
  }
362
- const layers = this.use(RenderLayerManagerKey);
363
- const renderLayer = layers.get(this.renderLayerName);
362
+ const renderLayer = this.use(SceneRenderTreeKey).get(this.renderLayerName);
364
363
  renderLayer.container.addChild(this.container);
365
364
  }
366
365
  onDestroy() {
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 { RenderLayerManagerKey } 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 layers = this.use(RenderLayerManagerKey);\n const renderLayer = layers.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,SAAS,uBAAuB;AAEhC,SAAS,YAAY,UAAAA,eAAc;;;ACFnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAgBP,IAAM,uBAAmD;AAAA,EACvD,IAAI;AAAA,EAEJ,WAAW;AAAA,IACT,MAAM,cAAc;AAAA,IACpB,UAAU,qBAAqB;AAAA,EACjC;AAAA,EAEA,MAAM,UACJ,OACA,eACkB;AAClB,QAAI,CAAC,eAAe,IAAK,QAAO;AAChC,QAAI,KAAK,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,KAAK,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,OAAO,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,UAAU,GAAG,GAAG,IAAI,EAAE;AACxC,gBAAM,SAAS,IAAI,QAAQ;AAAA,YACzB,QAAQ,YAAY;AAAA,YACpB;AAAA,UACF,CAAC;AAGD,gBAAM,WAAW,GAAG,QAAQ,IAAI,IAAI,EAAE;AACtC,iBAAO,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,cAAc;AAAA,EACzB,QAAQ;AACV;;;AC5GA,SAAS,QAAQ,OAAO,aAAAC,YAAW,qBAAqB;;;ACAxD,SAAS,WAAW,WAAW,oBAAoB;AACnD,SAAS,UAAAC,SAAQ,iBAAiB;AAClC,SAAS,6BAA6B;;;ACFtC,SAAS,wBAAwB;AACjC,SAAS,UAAAC,SAAQ,WAAAC,UAAS,aAAAC,kBAAiB;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,MAAMC,QAAO,IAAa,QAAQ;AACxC,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,KAAK,OAAO;AAEd,UAAM,WAAW,GAAG,KAAK,IAAI,IAAI,OAAO;AACxC,UAAM,MAAMA,QAAO,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,UAAUA,QAAO,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,IAAIC,SAAQ;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,OAAO,IAAIC,WAAU,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,iBAAiB;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,gBAAU;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,OAAOC,QAAO,IAAkB,QAAQ,MAAO;AACxE,QAAI,CAACD,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,UAAU;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,SAAS,KAAK,IAAI,qBAAqB;AAC7C,UAAM,cAAc,OAAO,IAAI,KAAK,eAAe;AACnD,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,SAAS;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;AAvJO;AAAM,oBAAN,gDADP,8BACa;AAAN,4BAAM;AAAN,IAAM,mBAAN;;;AD5BA,IAAM,sBAAN,cAAkC,OAAO;AAAA,EALhD,OAKgD;AAAA;AAAA;AAAA,EACrC,QAAQ,MAAM;AAAA,EACd,WAAW;AAAA;AAAA,EAEZ;AAAA,EAER,WAAW,SAA8B;AACvC,UAAM,aAAa,QAAQ,QAAQ,aAAa;AAChD,SAAK,QAAQ,WAAW,SAAS,CAACE,YAAW,gBAAgB,CAAC;AAAA,EAChE;AAAA,EAEA,SAAe;AACb,eAAW,UAAU,KAAK,OAAO;AAC/B,YAAM,YAAY,OAAO,IAAIA,UAAS;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,eAAW,IAAI,sBAAsB;AAGrC,UAAM,KAAK,QAAQ,WAAW,eAAe;AAC7C,QAAI,eAAe,YAAY;AAAA,MAC7B,MAAM,wBAACC,UAAiBC,QAAO,KAAmBD,KAAI,GAAhD;AAAA,MACN,QAAQ,wBAACA,UAAiB;AACxB,QAAAC,QAAO,OAAOD,KAAI;AAAA,MACpB,GAFQ;AAAA,IAGV,CAAC;AAAA,EACH;AAAA,EAEA,gBAAgB,WAAkC;AAChD,cAAU,IAAI,IAAI,oBAAoB,CAAC;AAAA,EACzC;AACF;;;AM9BA,SAAS,mBAAmB;AAIrB,SAAS,SAASE,OAAyC;AAChE,SAAO,IAAI,YAAY,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":["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/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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,uBAAuB;AAEhC,SAAS,YAAY,UAAAA,eAAc;;;ACFnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAgBP,IAAM,uBAAmD;AAAA,EACvD,IAAI;AAAA,EAEJ,WAAW;AAAA,IACT,MAAM,cAAc;AAAA,IACpB,UAAU,qBAAqB;AAAA,EACjC;AAAA,EAEA,MAAM,UACJ,OACA,eACkB;AAClB,QAAI,CAAC,eAAe,IAAK,QAAO;AAChC,QAAI,KAAK,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,KAAK,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,OAAO,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,UAAU,GAAG,GAAG,IAAI,EAAE;AACxC,gBAAM,SAAS,IAAI,QAAQ;AAAA,YACzB,QAAQ,YAAY;AAAA,YACpB;AAAA,UACF,CAAC;AAGD,gBAAM,WAAW,GAAG,QAAQ,IAAI,IAAI,EAAE;AACtC,iBAAO,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,cAAc;AAAA,EACzB,QAAQ;AACV;;;AC5GA,SAAS,QAAQ,OAAO,aAAAC,YAAW,qBAAqB;;;ACAxD,SAAS,WAAW,WAAW,oBAAoB;AACnD,SAAS,UAAAC,SAAQ,iBAAiB;AAClC,SAAS,0BAA0B;;;ACFnC,SAAS,wBAAwB;AACjC,SAAS,UAAAC,SAAQ,WAAAC,UAAS,aAAAC,kBAAiB;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,MAAMC,QAAO,IAAa,QAAQ;AACxC,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,KAAK,OAAO;AAEd,UAAM,WAAW,GAAG,KAAK,IAAI,IAAI,OAAO;AACxC,UAAM,MAAMA,QAAO,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,UAAUA,QAAO,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,IAAIC,SAAQ;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,OAAO,IAAIC,WAAU,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,iBAAiB;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,gBAAU;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,OAAOC,QAAO,IAAkB,QAAQ,MAAO;AACxE,QAAI,CAACD,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,UAAU;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,kBAAkB,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,SAAS;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,OAAO;AAAA,EALhD,OAKgD;AAAA;AAAA;AAAA,EACrC,QAAQ,MAAM;AAAA,EACd,WAAW;AAAA;AAAA,EAEZ;AAAA,EAER,WAAW,SAA8B;AACvC,UAAM,aAAa,QAAQ,QAAQ,aAAa;AAChD,SAAK,QAAQ,WAAW,SAAS,CAACE,YAAW,gBAAgB,CAAC;AAAA,EAChE;AAAA,EAEA,SAAe;AACb,eAAW,UAAU,KAAK,OAAO;AAC/B,YAAM,YAAY,OAAO,IAAIA,UAAS;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,eAAW,IAAI,sBAAsB;AAGrC,UAAM,KAAK,QAAQ,WAAW,eAAe;AAC7C,QAAI,eAAe,YAAY;AAAA,MAC7B,MAAM,wBAACC,UAAiBC,QAAO,KAAmBD,KAAI,GAAhD;AAAA,MACN,QAAQ,wBAACA,UAAiB;AACxB,QAAAC,QAAO,OAAOD,KAAI;AAAA,MACpB,GAFQ;AAAA,IAGV,CAAC;AAAA,EACH;AAAA,EAEA,gBAAgB,WAAkC;AAChD,cAAU,IAAI,IAAI,oBAAoB,CAAC;AAAA,EACzC;AACF;;;AM9BA,SAAS,mBAAmB;AAIrB,SAAS,SAASE,OAAyC;AAChE,SAAO,IAAI,YAAY,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":["Assets","Transform","Assets","Assets","Texture","Rectangle","Assets","Texture","Rectangle","config","tiledMap","Assets","Transform","path","Assets","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yagejs/tilemap",
3
- "version": "0.1.0",
3
+ "version": "0.2.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.1.0",
52
- "@yagejs/renderer": "^0.1.0",
51
+ "@yagejs/core": "^0.2.0",
52
+ "@yagejs/renderer": "^0.2.0",
53
53
  "@pixi/tilemap": "^5.0.0",
54
54
  "pixi.js": "^8.5.0"
55
55
  },
56
56
  "devDependencies": {
57
- "@yagejs/physics": "^0.1.0"
57
+ "@yagejs/physics": "^0.2.0"
58
58
  }
59
59
  }