UNPKG

evidently-pixi

Version:

TypeScript powered set of modules to make it easier to make games in Pixi.js.

179 lines 8.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const PIXI = require("pixi.js"); function assertTilesetConfigField(config, expectedLowerBound, fieldName) { if (config[fieldName] < expectedLowerBound) { throw new Error(`${fieldName} expected to be equal or larger to ${expectedLowerBound}, '${config[fieldName]}' given instead.`); } } function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string } /** * Provides simple API for retrieving texture by name, by a segment of a texture or by a tile in a tileset. * * The goal is to have a centralized source of textures that can be easily accessed just by a string. Simplifies * serialization among other things. * * To use this, a texture first has to be registered with a name, then you can access it by one of the many ways. * A tileset can also be registered in which case its tiles can be retrieved via `getTile()`. * * Note: `TextureStore` never creates new BaseTextures. What it means is that for the purpose of performance, all the textures * created from the same base texture are still part of that base texture, part of the same texture atlas. */ class TextureStore { /** * Creates a new Texture Factory. * * @param {string="/"} separator Used to delimit properties of a texture rectangle * @throws {Error} Thrown when separator's length is different than 1 character. */ constructor(separator = '/') { this.nameToTextureMap = new Map(); this.textureToNameMap = new Map(); this.nameToTilesetConfigMap = new Map(); if (separator.length !== 1) { throw new Error("Separator must always be of length 1."); } this._separator = separator; this._separatorRemovalRegex = new RegExp(`${escapeRegExp(separator)}.+`); } /** * Separator used to delimit properties of a dynamic texture rectangle */ get separator() { return this._separator; } /** * Registers a texture for use in the factory. * * @param {PIXI.Texture} texture Texture to register * @param {string} name Name of the texture to use for access * @throws {Error} Thrown when texture name contains the separator provided in the constructor. */ registerTexture(texture, name) { if (name.indexOf(this.separator) !== -1) { throw new Error(`Cannot register a texture that contains the separator character '${this.separator}' in its name.`); } this.nameToTextureMap.set(name, texture); this.textureToNameMap.set(texture, name); } /** * Registers a previously registered texture as a tileset, to allow using it with `getTile()` method. The texture can still be used * the same way it was used previously. * * @param {string} textureName Name of the texture to use as the basis for the tileset * @param {TilesetTextureConfig} config Tileset configuration * @throwns {Error} Thrown when you try to register tileset for `textureName` that was not previously registered. * @throwns {Error} Thrown when you try to register tileset for `textureName` that was already registered as tileset. */ registerTileset(textureName, config) { if (!this.nameToTextureMap.has(textureName)) { throw new Error(`Cannot register tileset for not-registered texture '${textureName}'.`); } if (this.nameToTilesetConfigMap.has(textureName)) { throw new Error(`Tileset for texture '${textureName}' is already defined!`); } assertTilesetConfigField(config, 0, 'offsetX'); assertTilesetConfigField(config, 0, 'offsetY'); assertTilesetConfigField(config, 0, 'spacingX'); assertTilesetConfigField(config, 0, 'spacingY'); assertTilesetConfigField(config, 1, 'tileWidth'); assertTilesetConfigField(config, 1, 'tileHeight'); this.nameToTilesetConfigMap.set(textureName, Object.assign({}, config)); } /** * Given a texture previously extracted from this factory returns its name. Most useful to get the generated name * of textures from `getTile()` or `getTextureRectangle()`. * * @param {string} texture Texture which name to get * @return {string} Name of the texture * @throws {Error} Thrown when texture was not previously registered nor generated. */ getTextureName(texture) { const name = this.textureToNameMap.get(texture); if (!name) { throw new Error("Texture was not registered."); } return name; } /** * Retrieves a texture by name, where the name can be either a base name of a texture or one with the additional properties, * as generated by `getTextureRectangle()` or `getTile()`. * If a name with properties is passed and that texture was not previously generated in this factory it'll work exactly the same * as if calling `getTextureRectangle()` with the basename and rectangle extracted. * * @param {string} name Name of the texture to retrieve * @return {PIXI.Texture} The texture for the name * @throws {Error} Thrown when texture for the given name was not found and did not have the valid number of properties. * @throws {Error} Thrown when the width or height in the texture name's properties is less than 1 */ getTexture(name) { const texture = this.nameToTextureMap.get(name); if (!texture) { const pieces = name.split(this.separator); if (pieces.length === 5) { const [baseName, x, y, width, height] = pieces; return this.getTextureRectangle(baseName, parseInt(x), parseInt(y), parseInt(width), parseInt(height)); } else { throw new Error(`Unknown texture '${name}'`); } } return texture; } /** * Retrieves a rectangle from a previously registered texture or a valid texture rectangle. If the name provided is * a texture rectangle, the position provided will be relative to that rectangle's frame, not the base texture's frame. * * @param {string} name Name of the texture to use as a basis * @param {number} x Offset X position from the top-left corner of the texture's frame * @param {number} y Offset Y position from the top-left corner of the texture's frame * @param {number} width Width of the new texture * @param {number} height Height of the new texture * @return {PIXI.Texture} The new texture that matches the specified frame. * @throws {Error} Thrown when either width or height is less than 1 */ getTextureRectangle(name, x, y, width, height) { const texture = this.getTexture(name); const baseName = name.replace(this._separatorRemovalRegex, ''); const baseTexture = this.getTexture(baseName); if (width <= 0) { throw new Error("Width must be a positive integer"); } if (height <= 0) { throw new Error("Height must be a positive integer"); } const newTexture = new PIXI.Texture(texture.baseTexture, new PIXI.Rectangle(texture.frame.x + x, texture.frame.y + y, width, height)); const newName = [ baseName, newTexture.frame.x - baseTexture.frame.x, newTexture.frame.y - baseTexture.frame.y, width, height ].join(this.separator); this.nameToTextureMap.set(newName, newTexture); this.textureToNameMap.set(newTexture, newName); return newTexture; } /** * Retrieves a texture that matches a tile at the given position in the tileset. * * @param {string} name Name of the tileset to use. * @param {number} x X position of the tile * @param {number} y Y position of the tile * @return {PIXI.Texture} The texture for the requested tile * @throws {Error} Thrown when the name of the texture was not registered as a tileset. */ getTile(name, x, y) { const config = this.nameToTilesetConfigMap.get(name); if (!config) { throw new Error(`No tileset registered for texture '${name}'.`); } const expectedX = config.offsetX + x * (config.tileWidth + config.spacingX); const expectedY = config.offsetY + y * (config.tileHeight + config.spacingY); return this.getTextureRectangle(name, expectedX, expectedY, config.tileWidth, config.tileHeight); } } exports.TextureStore = TextureStore; //# sourceMappingURL=TextureStore.js.map