UNPKG

spaceship-sprites

Version:

Spaceship Sprite is a random ship sprite generator in typescript.

213 lines (212 loc) 9.28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const _1 = require("."); const constants_1 = require("./constants"); const sprite_1 = require("./sprite"); const validator_1 = require("./validator"); class SpriteBuilder { constructor({ spriteDimensions = [7, 7], blankPercentage = 0.5, colorPallet = [_1.Color.random(), _1.Color.random(), _1.Color.random()], useRandomPallet = false, randomColorCount = 3, randomAlpha = false, border = 1, horizontalSymmetry = false, blankColor = _1.Color.WHITE }) { this.spriteDimensions = spriteDimensions; this.blankPercentage = blankPercentage; this.colorPallet = colorPallet; this.useRandomPallet = useRandomPallet; this.randomColorCount = randomColorCount; this.randomAlpha = randomAlpha; this.border = typeof border === 'number' ? [border, border, border, border] : border; this.horizontalSymmetry = horizontalSymmetry; this.blankColor = blankColor; this.validate(); } single() { let result = new sprite_1.default({ dim: this.spriteDimensions, colorFill: this.blankColor }); const realPallet = this.addBlanks(this.getPallet()); let i = 1; let m = 1; let queue = []; if (this.horizontalSymmetry) { m = 2; } for (let y = 0; y < Math.ceil(result.dim[constants_1.Dimension.Height] / m); y++) { i *= -1; let element = 0; for (let x = 0; x < result.dim[constants_1.Dimension.Width]; x++) { const selectedColor = this.selectColor(realPallet); if (element === Math.floor(result.dim[constants_1.Dimension.Width] / 2)) { result.setPixelAt(x, y, selectedColor); } else if (queue.length == element + 1) { let color = queue.pop(); if (color !== undefined) { result.setPixelAt(x, y, color); } else { throw new Error('Algorithm error. Expected an element when "queue.pop()" but got none.'); } } else { queue.push(selectedColor); result.setPixelAt(x, y, selectedColor); } if (element === Math.floor(result.dim[constants_1.Dimension.Width] / 2) || element === 0) { i *= -1; } element += i; } } this.result = result; return this; } withDim(dim) { if (this.result !== undefined) { throw new Error("Can't change the dimension after having a sprite already built."); } this.spriteDimensions = dim; this.validate(); return this; } withBorder(borders = this.border, borderColor = this.blankColor) { if (this.result === undefined) { throw new Error('No sprite is set on builder.'); } let result = new sprite_1.default({ dim: [ this.result.dim[constants_1.Dimension.Width] + borders[constants_1.Border.Left] + borders[constants_1.Border.Right], this.result.dim[constants_1.Dimension.Height] + borders[constants_1.Border.Up] + borders[constants_1.Border.Down] ], colorFill: borderColor }); for (let x = borders[constants_1.Border.Left], i = 0; i < this.result.dim[constants_1.Dimension.Width]; x++, i++) { for (let y = borders[constants_1.Border.Up], j = 0; j < this.result.dim[constants_1.Dimension.Height]; y++, j++) { result.setPixelAt(x, y, this.result.pixelAt(i, j)); } } this.result = result; return this; } withEdges(edgeColor = _1.Color.BLACK, edgeWeight = 0.7, addExtraBorder = true) { if (this.result === undefined) { throw new Error('No sprite is set on builder.'); } if (addExtraBorder) { this.withBorder([1, 1, 1, 1]); } for (let x = 0; x < this.result.dim[constants_1.Dimension.Width]; x++) { for (let y = 0; y < this.result.dim[constants_1.Dimension.Height]; y++) { let pixel = this.result.pixelAt(x, y); if (pixel.equals(edgeColor)) break; if (!pixel.equals(this.blankColor)) { this.result.setPixelAtChecked(x, y - 1, pixel.mixWeighed(edgeColor, edgeWeight)); break; } } } for (let y = 0; y < this.result.dim[constants_1.Dimension.Height]; y++) { for (let x = 0; x < this.result.dim[constants_1.Dimension.Width]; x++) { let pixel = this.result.pixelAt(x, y); if (pixel.equals(edgeColor)) break; if (!pixel.equals(this.blankColor)) { this.result.setPixelAtChecked(x - 1, y, pixel.mixWeighed(edgeColor, edgeWeight)); this.result.setPixelAtChecked(this.result.dim[constants_1.Dimension.Width] - x, y, pixel.mixWeighed(edgeColor, edgeWeight)); break; } } } for (let x = 0; x < this.result.dim[constants_1.Dimension.Width]; x++) { for (let y = this.result.dim[constants_1.Dimension.Height] - 1; y > 0; y--) { let pixel = this.result.pixelAt(x, y); if (pixel.equals(edgeColor)) break; if (!pixel.equals(this.blankColor)) { this.result.setPixelAtChecked(x, y + 1, pixel.mixWeighed(edgeColor, edgeWeight)); break; } } } return this; } transform(func) { if (this.result === undefined) { throw new Error('No sprite is set on builder.'); } for (let x = 0; x < this.result.dim[0]; x++) { for (let y = 0; y < this.result.dim[1]; y++) { let pixel = this.result.pixelAt(x, y); this.result.setPixelAt(x, y, func(this.result.dim, x, y, pixel)); } } return this; } withPadding(dim, paddingColor = this.blankColor) { if (this.result === undefined) { throw new Error('No sprite is set on builder.'); } if (dim[0] < this.result.dim[0]) { throw new Error(`Cannot set padding because ${dim[0]} is less than the existing width of ${this.result.dim[0]}`); } if (dim[1] < this.result.dim[1]) { throw new Error(`Cannot set padding because ${dim[1]} is less than the existing height of ${this.result.dim[1]}`); } let old = this.result; this.result = new sprite_1.default({ dim: dim, colorFill: paddingColor }); let leftOffset = Math.floor((dim[0] - old.dim[0]) / 2); let topOffset = Math.floor((dim[1] - old.dim[1]) / 2); for (let x = leftOffset, i = 0; i < old.dim[0]; x++, i++) { for (let y = topOffset, j = 0; j < old.dim[1]; y++, j++) { this.result.setPixelAt(x, y, old.pixelAt(i, j)); } } return this; } build() { if (this.result === undefined) { throw new Error('Resulting sprite is not valid.'); } let result = this.result; this.result = undefined; return result; } getPallet() { if (this.useRandomPallet) return SpriteBuilder.randomPallet(this.randomColorCount, this.randomAlpha); else return this.colorPallet; } selectColor(pallet) { return pallet[SpriteBuilder.randInt(0, pallet.length - 1)]; } addBlanks(pallet) { const blanksToInsert = Math.round((pallet.length * this.blankPercentage) / (1 - this.blankPercentage)); return [...pallet].concat(...new Array(blanksToInsert) .fill(null) .map(() => this.blankColor.copy())); } static randInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } static randomPallet(colorCount, randomAlpha) { validator_1.default.positive(colorCount, 'colorCount'); return Array.from({ length: colorCount }, () => _1.Color.random(randomAlpha)); } validate() { validator_1.default.positive(this.spriteDimensions[0], 'this.spriteDimensions[0]'); validator_1.default.positive(this.spriteDimensions[1], 'this.spriteDimensions[1]'); validator_1.default.percentage(this.blankPercentage, 'blankPercentage'); for (let i = 0; i < this.border.length; i++) { validator_1.default.positiveInteger(this.border[i], `border[${i}]`); } } } exports.default = SpriteBuilder;