UNPKG

@beetpx/beetpx

Version:

A TypeScript framework for pixel art browser games.

91 lines 3.83 kB
import { decode as fastPngDecode } from "fast-png"; import { Logger } from "../logger/Logger"; export class AssetLoader { #assets; #decodeAudioData; constructor(assets, params) { this.#assets = assets; this.#decodeAudioData = params.decodeAudioData; } async loadAssets(assetsToLoad) { const normalizedAssetsToLoad = assetsToLoad .map(url => url.trim()) .filter(url => url.length > 0); const unrecognizedAssetFormats = normalizedAssetsToLoad.filter(url => !this.#isImage(url) && !this.#isSound(url) && !this.#isJson(url)); if (unrecognizedAssetFormats.length > 0) { throw Error("Assets: following URLs don't look like any of supported formats: " + unrecognizedAssetFormats.map(url => `"${url}"`).join(", ") + '. Supported formats are: ".png", ".wav", ".flac", ".json", ".ldtk"'); } await Promise.all([ ...normalizedAssetsToLoad .filter(url => this.#isImage(url)) .map(url => this.#loadImage(url)), ...normalizedAssetsToLoad .filter(url => this.#isSound(url)) .map(url => this.#loadSound(url)), ...normalizedAssetsToLoad .filter(url => this.#isJson(url)) .map(url => this.#loadJson(url)), ]); } #isImage(url) { return url.toLowerCase().endsWith(".png"); } #isSound(url) { return (url.toLowerCase().endsWith(".wav") || url.toLowerCase().endsWith(".flac")); } #isJson(url) { return (url.toLowerCase().endsWith(".json") || url.toLowerCase().endsWith(".ldtk")); } async #loadImage(url) { Logger.infoBeetPx(`Assets: loading image "${url}"`); const httpResponse = await fetch(this.#withPathFixed(url)); if (!this.#is2xx(httpResponse.status)) { throw Error(`Assets: could not fetch image file: "${url}"`); } const arrayBuffer = await httpResponse.arrayBuffer(); const decodedPng = fastPngDecode(arrayBuffer); if (decodedPng.channels !== 3 && decodedPng.channels !== 4) { throw Error(`Assets: only PNG image files with 3 or 4 channels are supported. The file which seems to have ${decodedPng.channels} channels instead: "${url}"`); } this.#assets.addImageAsset(url, { width: decodedPng.width, height: decodedPng.height, channels: decodedPng.channels, rgba8bitData: decodedPng.data, }); } async #loadSound(url) { Logger.infoBeetPx(`Assets: loading sound "${url}"`); const httpResponse = await fetch(this.#withPathFixed(url)); if (!this.#is2xx(httpResponse.status)) { throw Error(`Assets: could not fetch sound file: "${url}"`); } const arrayBuffer = await httpResponse.arrayBuffer(); const audioBuffer = await this.#decodeAudioData(arrayBuffer); this.#assets.addSoundAsset(url, { audioBuffer }); } async #loadJson(url) { Logger.infoBeetPx(`Assets: loading JSON "${url}"`); const httpResponse = await fetch(this.#withPathFixed(url)); if (!this.#is2xx(httpResponse.status)) { throw Error(`Assets: could not fetch JSON file: "${url}"`); } const json = await httpResponse.json(); this.#assets.addJsonAsset(url, { json }); } #withPathFixed(url) { if (BEETPX__IS_PROD) { return url; } if (url.startsWith("http://") || url.startsWith("https://")) { return url; } return url.startsWith("/") ? url : `/${url}`; } #is2xx(httpStatus) { return httpStatus >= 200 && httpStatus < 300; } } //# sourceMappingURL=AssetLoader.js.map