avocado-old/packages/topdown/tiles.js

133 lines
2.9 KiB
JavaScript
Raw Normal View History

2019-03-27 01:05:29 -05:00
import * as I from 'immutable';
2019-04-28 23:45:03 -05:00
import {compose, EventEmitter} from '@avocado/core';
2019-03-25 19:03:34 -05:00
import {Rectangle, Vector} from '@avocado/math';
2019-05-13 21:07:51 -05:00
import {TileUpdatePacket} from './packets/tile-update.packet';
2019-03-25 19:03:34 -05:00
const decorate = compose(
EventEmitter,
2019-03-25 19:03:34 -05:00
Vector.Mixin('size', 'width', 'height', {
default: [0, 0],
}),
);
2019-04-16 17:52:56 -05:00
export class Tiles extends decorate(class {}) {
2019-03-25 19:03:34 -05:00
2019-05-13 21:07:51 -05:00
constructor(json) {
super();
2019-05-13 21:07:51 -05:00
this.data = [];
2019-05-27 21:51:21 -05:00
this.updatePackets = [];
2019-05-13 21:07:51 -05:00
if ('undefined' !== typeof json) {
this.fromJSON(json);
}
}
acceptPacket(packet) {
if (packet instanceof TileUpdatePacket) {
2019-05-27 21:51:21 -05:00
const unpackedPosition = [
packet.data.position & 0xFFFF,
packet.data.position >> 16,
];
this.setTileAt(unpackedPosition, packet.data.tile);
2019-05-13 21:07:51 -05:00
}
2019-03-27 01:05:29 -05:00
}
2019-04-12 20:16:31 -05:00
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) {
2019-05-13 21:07:51 -05:00
fn(this.data[i], x, y, i);
2019-04-12 20:16:31 -05:00
++i;
++x;
}
x = 0;
++y;
}
}
fromJSON(json) {
if (json.size) {
this.size = json.size;
}
if (json.data) {
2019-05-13 21:07:51 -05:00
this.data = json.data.slice(0);
2019-04-12 20:16:31 -05:00
}
return this;
}
2019-06-12 22:15:56 -05:00
indexAt(position) {
return this.width * position[1] + position[0];
}
2019-05-27 21:51:21 -05:00
packetsForUpdate() {
const packetsForUpdate = this.updatePackets;
this.updatePackets = [];
return packetsForUpdate;
}
2019-03-25 19:03:34 -05:00
get rectangle() {
return Rectangle.compose([0, 0], this.size);
}
setTileAt(position, tile) {
const oldTile = this.tileAt(position);
if (oldTile === tile) {
return;
}
const index = position[1] * this.width + position[0];
2019-05-13 21:07:51 -05:00
if (index < 0 || index >= this.data.length) {
2019-03-25 20:49:16 -05:00
return;
}
2019-05-13 21:07:51 -05:00
this.data[index] = tile;
2019-05-27 21:51:21 -05:00
const packedPosition = position[1] << 16 | position[0];
this.updatePackets.push(new TileUpdatePacket({
position: packedPosition,
tile,
}));
this.emit('dataChanged');
2019-03-25 20:49:16 -05:00
}
2019-03-25 19:03:34 -05:00
slice(rectangle) {
const tilesRectangle = this.rectangle;
2019-03-25 20:49:42 -05:00
// Get intersection.
2019-03-25 19:03:34 -05:00
if (!Rectangle.intersects(rectangle, tilesRectangle)) {
return [];
}
2019-03-25 20:49:42 -05:00
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) {
2019-05-13 21:07:51 -05:00
slice[sliceRow + x] = this.data[dataRow + x];
2019-03-25 19:03:34 -05:00
x++;
}
2019-03-25 20:49:42 -05:00
sliceRow += sliceWidth;
dataRow += dataWidth;
x -= sliceWidth;
2019-03-25 19:03:34 -05:00
}
return slice;
}
tileAt(position) {
2019-06-12 22:15:56 -05:00
return this.data[this.indexAt(position)];
2019-03-25 19:03:34 -05:00
}
toJSON() {
2019-03-25 20:50:11 -05:00
return {
2019-05-13 21:07:51 -05:00
size: Vector.copy(this.size),
data: this.data.slice(0),
2019-03-25 20:50:11 -05:00
};
2019-03-25 19:03:34 -05:00
}
}