// NOTE: It's super not clear how much of this should be in rust vs // javascript. Dealing with the level code is really nice in javascript // but there's a bunch of weird stuff that really feels lower level. import { load_texture } from "./assets"; import { Texture, print, spr, use_texture } from "./graphics"; import { load_string } from "./io"; // TODO: Use io-ts? YIKES. export type Tile = { px: [number, number]; src: [number, number]; f: number; t: number; a: number; }; export type TileLayer = { type: "tile"; texture: Texture; grid_size: number; offset: [number, number]; tiles: Tile[]; }; export type Layer = TileLayer; export type Level = { world_x: number; world_y: number; width: number; height: number; layers: Layer[]; }; export type TileSet = { id: number; texture: Texture }; export type World = { levels: Level[]; tilesets: Map }; async function load_tileset(def: { uid: number; relPath: string; }): Promise { let relPath = def.relPath as string; if (relPath.endsWith(".aseprite")) { // Whoops let's load the export instead? relPath = relPath.substring(0, relPath.length - 8) + "png"; } let texture = await load_texture(relPath); print("Loaded tileset", def.uid, "from", relPath, "as ID", texture.id()); return { id: def.uid, texture }; } function load_level( tile_sets: Map, def: { worldX: number; worldY: number; pxWid: number; pxHei: number; layerInstances: { __gridSize: number; __pxTotalOffsetX: number; __pxTotalOffsetY: number; __tilesetDefUid: number; gridTiles: { px: [number, number]; src: [number, number]; f: number; t: number; a: number; }[]; }[]; } ): Level { return { world_x: def.worldX, world_y: def.worldY, width: def.pxWid, height: def.pxHei, layers: def.layerInstances.map((li) => { const tileset = tile_sets.get(li.__tilesetDefUid); if (!tileset) { throw new Error("Unable to find texture!!! " + li.__tilesetDefUid); } return { type: "tile", texture: tileset.texture, grid_size: li.__gridSize, offset: [li.__pxTotalOffsetX, li.__pxTotalOffsetY], tiles: li.gridTiles, }; }), }; } export async function load_world(path: string): Promise { print("Loading map:", path); const blob = await load_string(path); const map = JSON.parse(blob); const tilesets = new Map(); let loaded_tilesets = await Promise.all( map.defs.tilesets .filter((def: any) => def.relPath != null) .map((def: any) => load_tileset(def)) ); for (const ts of loaded_tilesets) { tilesets.set(ts.id, ts); } const levels = map.levels.map((l: any) => load_level(tilesets, l)); return { levels, tilesets }; } export function draw_level( level: Level, offset_x: number = 0, offset_y: number = 0 ) { for (const layer of level.layers) { use_texture(layer.texture); let [ofx, ofy] = layer.offset; ofx += offset_x; ofy += offset_y; for (const tile of layer.tiles) { // TODO: Flip and whatnot. spr( tile.px[0] + ofx, tile.px[1] + ofy, layer.grid_size, layer.grid_size, tile.src[0], tile.src[1] ); } } }