import * as I from 'immutable'; import {compose} from '@avocado/core'; import {Rectangle, Vector} from '@avocado/math'; import {EventEmitter} from '@avocado/mixins'; const decorate = compose( EventEmitter, Vector.Mixin('size', 'width', 'height', { default: [0, 0], }), ); export class Tiles extends decorate(class {}) { constructor() { super(); this.data = I.List(); this._state = I.Map(); } acceptStateChange(change) { if (change.width) { this.width = change.width; } if (change.height) { this.height = change.height; } if (change.data) { const oldData = this.data; for (const i in change.data) { const index = parseInt(i); this.data = this.data.set(index, change.data[i]); } if (oldData !== this.data) { this.emit('dataChanged'); } } } fromJSON(json) { if (json.size) { this.size = json.size; } if (json.data) { this.data = I.fromJS(json.data); } return this; } get rectangle() { return Rectangle.compose([0, 0], this.size); } setTileAt(x, y, tile) { const oldTile = this.tileAt(x, y); if (oldTile === tile) { return; } const index = y * this.width + x; if (index < 0 || index >= this.data.size) { return; } this.data = this.data.set(index, tile); this.emit('dataChanged'); } 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.get(dataRow + x); x++; } sliceRow += sliceWidth; dataRow += dataWidth; x -= sliceWidth; } return slice; } get state() { return this._state; } tick(elapsed) { this._state = this._state.set('width', this.width); this._state = this._state.set('height', this.height); this._state = this._state.set('data', this.data); } tileAt(x, y) { return this.data.get(y * this.width + x); } toJSON() { return { size: [...this.size], data: [...this.data.toJS()], }; } }