96 lines
3.2 KiB
JavaScript
96 lines
3.2 KiB
JavaScript
// tiledLoader.js : charge une map Tiled (.tmj + .tsx) et la dessine en iso
|
|
|
|
import { Sprite, Assets } from 'pixi.js';
|
|
import { iso, getTw, getTh } from './renderer.js';
|
|
|
|
|
|
export async function loadTiledMap(mapPath) {
|
|
// baseUrl = dossier du .tmj (les .tsx sont a cote)
|
|
const baseUrl = mapPath.substring(0, mapPath.lastIndexOf('/') + 1);
|
|
const map = await fetch(mapPath).then(r => r.json());
|
|
|
|
// parse les .tsx (XML) referencements (firstgid + chemin image par tile id)
|
|
const tilesets = [];
|
|
for (const ts of map.tilesets) {
|
|
const tsxText = await fetch(baseUrl + ts.source).then(r => r.text());
|
|
const xml = new DOMParser().parseFromString(tsxText, 'text/xml');
|
|
const tiles = {};
|
|
for (const tile of xml.querySelectorAll('tile')) {
|
|
const id = parseInt(tile.getAttribute('id'));
|
|
const img = tile.querySelector('image');
|
|
if (img) {
|
|
tiles[id] = {
|
|
src: baseUrl + img.getAttribute('source'),
|
|
w: parseInt(img.getAttribute('width')),
|
|
h: parseInt(img.getAttribute('height')),
|
|
};
|
|
}
|
|
}
|
|
tilesets.push({ firstgid: ts.firstgid, tiles });
|
|
}
|
|
|
|
// precharger toutes les textures
|
|
const urls = [];
|
|
for (const ts of tilesets) {
|
|
for (const id in ts.tiles) urls.push(ts.tiles[id].src);
|
|
}
|
|
await Assets.load(urls);
|
|
|
|
return { map, tilesets };
|
|
}
|
|
|
|
|
|
function _gidToTile(gid, tilesets) {
|
|
// chercher dans le bon tileset (firstgid descendant)
|
|
for (let i = tilesets.length - 1; i >= 0; i--) {
|
|
if (gid >= tilesets[i].firstgid) {
|
|
return tilesets[i].tiles[gid - tilesets[i].firstgid] || null;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
export function drawTiledMap(layer, data) {
|
|
const { map, tilesets } = data;
|
|
const W = map.width;
|
|
const H = map.height;
|
|
const tw = getTw();
|
|
const th = getTh();
|
|
|
|
// reference : la base (footprint iso) d'un sprite Kenney fait 256x128 px
|
|
// au tw courant, on veut que cette base remplisse 1 unite monde (tw x th px)
|
|
const REF_TILE_W = 256;
|
|
const scale = tw / REF_TILE_W;
|
|
|
|
for (const tlayer of map.layers) {
|
|
if (tlayer.type !== 'tilelayer') continue;
|
|
if (tlayer.visible === false) continue;
|
|
|
|
for (let i = 0; i < tlayer.data.length; i++) {
|
|
const gid = tlayer.data[i];
|
|
if (gid === 0) continue; // 0 = case vide
|
|
|
|
const tile = _gidToTile(gid, tilesets);
|
|
if (!tile) continue;
|
|
|
|
const col = i % W;
|
|
const row = Math.floor(i / W);
|
|
// centrer la map sur (0, 0)
|
|
const wx = col - (W - 1) / 2;
|
|
const wy = row - (H - 1) / 2;
|
|
|
|
const tex = Assets.get(tile.src);
|
|
if (!tex) continue;
|
|
|
|
const sprite = new Sprite(tex);
|
|
sprite.anchor.set(0.5, 1.0); // base centree sur la tile, le sprite "monte"
|
|
const p = iso(wx, wy);
|
|
sprite.x = p.x;
|
|
sprite.y = p.y + th / 2; // decalage half pour que la pointe basse de la diamond touche la base
|
|
sprite.scale.set(scale);
|
|
layer.addChild(sprite);
|
|
}
|
|
}
|
|
}
|