avocado-old/packages/topdown/layer.js
2019-05-27 21:51:21 -05:00

217 lines
5.0 KiB
JavaScript

import {compose, EventEmitter, Property} from '@avocado/core';
import {Entity, EntityCreatePacket, EntityList} from '@avocado/entity';
import {Vector} from '@avocado/math';
import {ShapeList} from '@avocado/physics';
import {Synchronized} from '@avocado/state';
import {Tiles} from './tiles';
import {Tileset} from './tileset';
import {LayerCreatePacket} from './packets/layer-create.packet';
import {TileUpdatePacket} from './packets/tile-update.packet';
const decorate = compose(
EventEmitter,
Property('tilesetUri', {
track: true,
}),
Property('tileset', {
track: true,
}),
Property('world', {
track: true,
}),
Synchronized,
);
export class Layer extends decorate(class {}) {
constructor(json) {
super();
this.entityList = new EntityList();
this.index = -1;
this.tileGeometry = [];
this.tiles = new Tiles();
// Listeners.
this.entityList.on('entityAdded', this.onEntityAddedToLayer, this);
this.entityList.on('entityRemoved', this.onEntityRemovedFromLayer, this);
this.tiles.on('dataChanged', this.onTileDataChanged, this);
this.on('tilesetChanged', this.onTilesetChanged, this);
this.on('tilesetUriChanged', this.onTilesetUriChanged, this);
this.on('worldChanged', this.onWorldChanged, this);
if ('undefined' !== typeof json) {
this.fromJSON(json);
}
}
acceptPacket(packet) {
if (packet instanceof TileUpdatePacket) {
this.tiles.acceptPacket(packet);
}
if (packet instanceof EntityCreatePacket) {
this.entityList.acceptPacket(packet);
}
}
addEntity(entity) {
this.entityList.addEntity(entity);
}
addTileGeometry() {
const tileset = this.tileset;
if (!tileset) {
return false;
}
const world = this.world;
if (!world) {
return false;
}
const halfTileSize = Vector.scale(tileset.tileSize, 0.5);
this.tiles.forEachTile((tile, x, y, i) => {
const shape = this.tileset.geometry(tile);
if (!shape) {
return;
}
shape.position = Vector.add(
halfTileSize,
Vector.mul([x, y], tileset.tileSize),
);
const body = world.createBody(shape);
body.static = true;
world.addBody(body);
this.tileGeometry.push(body);
});
return true;
}
allEntities() {
return Array.from(this.entityList);
}
destroy() {
this.entityList.destroy();
this.entityList.off('entityAdded', this.onEntityAddedToLayer);
this.entityList.off('entityRemoved', this.onEntityRemovedFromLayer);
this.tiles.off('dataChanged', this.onTileDataChanged);
this.off('tilesetUriChanged', this.onTilesetUriChanged);
if (this.tileset) {
this.tileset.destroy();
}
}
findEntity(uuid) {
return this.entityList.findEntity(uuid);
}
fromJSON(json) {
if (json.entities) {
this.entityList.fromJSON(json.entities);
}
if (json.tiles) {
this.tiles.fromJSON(json.tiles)
}
if (json.tilesetUri) {
this.tilesetUri = json.tilesetUri;
}
return this;
}
onEntityAddedToLayer(entity) {
entity.setIntoLayer(this);
this.emit('entityAdded', entity)
}
onEntityRemovedFromLayer(entity) {
entity.removeFromLayer();
this.emit('entityRemoved', entity);
}
onTileDataChanged() {
this.emit('tileDataChanged');
}
onTilesetChanged(oldTileset) {
let didChange = false;
if (oldTileset) {
this.removeTileGeometry();
didChange = true;
}
if (this.addTileGeometry()) {
didChange = true;
}
if (didChange) {
this.emit('tileGeometryChanged');
}
}
onTilesetUriChanged() {
if (!this.tilesetUri) {
return;
}
Tileset.load(this.tilesetUri).then((tileset) => {
this.tileset = tileset;
});
}
onWorldChanged(oldWorld) {
let didChange = false;
if (oldWorld) {
this.removeTileGeometry();
didChange = true;
}
if (this.addTileGeometry()) {
didChange = true;
}
if (didChange) {
this.emit('tileGeometryChanged');
}
}
packetsForUpdate(force = false) {
const packets = [];
// Create layer during a force.
if (force) {
packets.push(new LayerCreatePacket(this.toJSON()));
}
const entityListPackets = this.entityList.packetsForUpdate(force);
for (let i = 0; i < entityListPackets.length; i++) {
packets.push(entityListPackets[i]);
}
if (!force) {
const tilesPackets = this.tiles.packetsForUpdate();
for (let i = 0; i < tilesPackets.length; ++i) {
tilesPackets[i].data.layer = this.index;
packets.push(tilesPackets[i]);
}
}
return packets;
}
removeEntity(entity) {
this.entityList.removeEntity(entity);
}
removeTileGeometry() {
// ... tag geometry in world for removal?
}
setTileAt(position, tile) {
this.tiles.setTileAt(position, tile);
}
tick(elapsed) {
this.entityList.tick(elapsed);
}
toJSON() {
return {
tilesetUri: this.tilesetUri,
tiles: this.tiles.toJSON(),
};
}
visibleEntities(query) {
return this.entityList.visibleEntities(query);
}
}