blob2d
Version:
Typed Modular 2D Game Engine for Web
141 lines (114 loc) • 3.34 kB
text/typescript
import {
ITiledFiniteTileLayer,
ITiledInfiniteTileLayer,
ITiledMapJSON,
} from './types';
type ITiledLayer = ITiledFiniteTileLayer | ITiledInfiniteTileLayer;
type SpritesIteratee<T> = (tileGID: number, x: number, y: number) => T;
type TilesIteratee<T> = (
tileGIDs: number[],
columns: number,
x: number,
y: number
) => T;
export class TiledMapper {
public readonly tileSize: number;
protected layers: Map<string, ITiledLayer>;
constructor(map: ITiledMapJSON) {
this.layers = new Map();
this.tileSize = map.tilewidth;
for (let i = 0; i < map.layers.length; i++) {
const layer = map.layers[i];
if (layer.type === 'tilelayer') {
this.layers.set(layer.name, layer);
}
}
}
public querySprite<T>(name: string, iteratee: SpritesIteratee<T>): T {
const [result] = this.queryAllSprites<T>(name, iteratee, true);
if (result === undefined) {
throw new Error(`No sprite named "${name}" was found.`);
}
return result;
}
public queryAllSprites<T>(
name: string,
iteratee: SpritesIteratee<T>,
first?: boolean
): T[] {
const layer = this.layers.get(name);
const results: T[] = [];
// skip processing wrong layer
if (layer === undefined) {
return results;
}
// process infinite tilelayer
if ('chunks' in layer) {
for (let j = 0; j < layer.chunks.length; j++) {
const chunk = layer.chunks[j];
for (let index = 0; index < chunk.data.length; index++) {
const tileGID = chunk.data[index];
if (tileGID > 0) {
const col = (index % chunk.width) + chunk.x;
const row = Math.floor(index / chunk.width) + chunk.y;
results.push(
iteratee(tileGID, col * this.tileSize, row * this.tileSize)
);
if (first && results.length > 0) {
return results;
}
}
}
}
} else {
// process finite tilelayer
for (let index = 0; index < layer.data.length; index++) {
const tileGID = layer.data[index];
if (tileGID > 0) {
const col = (index % layer.width) + layer.x;
const row = Math.floor(index / layer.width) + layer.y;
results.push(
iteratee(tileGID, col * this.tileSize, row * this.tileSize)
);
if (first && results.length > 0) {
return results;
}
}
}
}
return results;
}
public queryAllTiles<T>(name: string, iteratee: TilesIteratee<T>): T[] {
const layer = this.layers.get(name);
const results: T[] = [];
// skip processing wrong layer
if (layer === undefined) {
return results;
}
// process infinite tilelayer
if ('chunks' in layer) {
for (let j = 0; j < layer.chunks.length; j++) {
const chunk = layer.chunks[j];
results.push(
iteratee(
chunk.data,
chunk.width,
chunk.x * this.tileSize,
chunk.y * this.tileSize
)
);
}
} else {
// process finite tilelayer
results.push(
iteratee(
layer.data,
layer.width,
layer.x * this.tileSize,
layer.y * this.tileSize
)
);
}
return results;
}
}