spaceship-sprites
Version:
Spaceship Sprite is a random ship sprite generator in typescript.
213 lines (212 loc) • 9.28 kB
JavaScript
"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;