avocado-old/packages/topdown/tiles.js
2020-06-15 17:26:20 -05:00

147 lines
3.0 KiB
JavaScript

import * as I from 'immutable';
import {compose, EventEmitter} from '@avocado/core';
import {Rectangle, Vector} from '@avocado/math';
import TilesUpdatePacket from './packets/tiles-update.packet';
const CHUNK_AXIS = 10;
const decorate = compose(
EventEmitter,
Vector.Mixin('size', 'width', 'height', {
default: [0, 0],
}),
);
export class Tiles extends decorate(class {}) {
constructor(json) {
super();
this.data = [];
this._packets = [];
if ('undefined' !== typeof json) {
this.fromJSON(json);
}
}
acceptPacket(packet) {
if (packet instanceof TilesUpdatePacket) {
this.setTileAt(packet.data.position, packet.data.tile);
}
}
cleanPackets() {
this._packets = [];
}
// forEachTile(fn) {
// let [x, y] = [0, 0];
// let [width, height] = this.size;
// let i = 0;
// for (let k = 0; k < height; ++k) {
// for (let j = 0; j < width; ++j) {
// fn(this.data[i], x, y, i);
// ++i;
// ++x;
// }
// x = 0;
// ++y;
// }
// }
fromJSON(json) {
if (json.size) {
super.size = json.size;
}
if (json.data && json.data.length > 0) {
this.data = json.data.slice(0);
}
// Instantiate blank tiles if we got size but no data.
else {
this.data = Array(Vector.area(this.size)).fill(0);
}
return this;
}
indexAt(position) {
return this.width * position[1] + position[0];
}
packets(informed) {
return this._packets;
}
get rectangle() {
return Rectangle.compose([0, 0], this.size);
}
setTileAt(position, tile) {
const oldTile = this.tileAt(position);
if (oldTile === tile) {
return;
}
const index = this.indexAt(position);
if (index < 0 || index >= this.data.length) {
return;
}
this.data[index] = tile;
this._packets.push(new TilesUpdatePacket({
position,
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[dataRow + x];
x++;
}
sliceRow += sliceWidth;
dataRow += dataWidth;
x -= sliceWidth;
}
return slice;
}
tileAt(position) {
const index = this.indexAt(position);
if (index < 0 || index >= this.data.length) {
return;
}
return this.data[index];
}
toJSON() {
return {
size: this.size,
data: this.data,
};
}
toNetwork(informed) {
return {
size: this.size,
data: this.data,
};
}
}