import * as I from 'immutable'; import {compose} from '@avocado/core'; import {Rectangle, Vector} from '@avocado/math'; const decorate = compose( Vector.Mixin('size', 'width', 'height', { default: [0, 0], }), ); class TilesBase { constructor() { this._sizeState = I.List(); this._state = I.Map(); } acceptStateChange(change) { if (change.size) { this.size = change.size; } if (change.data) { this.data = change.data; } } fromJSON(json) { if (json.size) { this.size = json.size; } if (json.data) { this.data = json.data; } return this; } get rectangle() { return Rectangle.compose([0, 0], this.size); } setTileAt(x, y, tile) { const index = y * this.width + x; if (index < 0 || index >= this.data.length) { return; } this.data[index] = tile; } slice(rectangle) { const tilesRectangle = this.rectangle; // Get intersection. if (!Rectangle.intersects(rectangle, tilesRectangle)) { return []; } let [x, y, sliceWidth, sliceHeight] = Rectangle.intersection( rectangle, tilesRectangle, ); // No muls in the loop. let sliceRow = y * sliceWidth; const dataWidth = this.width; let dataRow = y * dataWidth; // Copy slice. const slice = new Array(sliceWidth * sliceHeight); for (let j = 0; j < sliceHeight; ++j) { for (let i = 0; i < sliceWidth; ++i) { slice[sliceRow + x] = this.data[dataRow + x]; x++; } sliceRow += sliceWidth; dataRow += dataWidth; x -= sliceWidth; } return slice; } get state() { return this._state; } tick(elapsed) { this._sizeState = this._sizeState.set(0, this.width); this._sizeState = this._sizeState.set(1, this.height); this._state = this._state.set('size', this._sizeState); this._state = this._state.set('data', this.data); } tileAt(x, y) { return this.data[y * this.width + x]; } toJSON() { return { size: [...this.size], data: [...this.data], }; } } export class Tiles extends decorate(TilesBase) {}