2019-04-28 23:45:03 -05:00
|
|
|
import {compose, EventEmitter, Property} from '@avocado/core';
|
2019-05-13 21:07:51 -05:00
|
|
|
import {Entity, EntityCreatePacket, EntityList} from '@avocado/entity';
|
2019-04-12 20:16:31 -05:00
|
|
|
import {Vector} from '@avocado/math';
|
2019-04-13 13:38:18 -05:00
|
|
|
import {ShapeList} from '@avocado/physics';
|
2019-04-07 11:43:50 -05:00
|
|
|
import {Synchronized} from '@avocado/state';
|
2019-03-28 12:31:41 -05:00
|
|
|
|
|
|
|
import {Tiles} from './tiles';
|
2019-04-12 18:49:07 -05:00
|
|
|
import {Tileset} from './tileset';
|
2019-05-13 21:07:51 -05:00
|
|
|
import {LayerCreatePacket} from './packets/layer-create.packet';
|
|
|
|
import {TileUpdatePacket} from './packets/tile-update.packet';
|
2019-03-25 23:39:44 -05:00
|
|
|
|
2019-03-27 01:52:24 -05:00
|
|
|
const decorate = compose(
|
|
|
|
EventEmitter,
|
|
|
|
Property('tilesetUri', {
|
|
|
|
track: true,
|
|
|
|
}),
|
2019-04-12 18:49:07 -05:00
|
|
|
Property('tileset', {
|
|
|
|
track: true,
|
|
|
|
}),
|
2019-04-12 20:16:31 -05:00
|
|
|
Property('world', {
|
|
|
|
track: true,
|
|
|
|
}),
|
2019-04-16 17:52:56 -05:00
|
|
|
Synchronized,
|
2019-03-27 01:52:24 -05:00
|
|
|
);
|
|
|
|
|
2019-04-16 17:52:56 -05:00
|
|
|
export class Layer extends decorate(class {}) {
|
2019-03-25 23:39:44 -05:00
|
|
|
|
2019-05-13 21:07:51 -05:00
|
|
|
constructor(json) {
|
2019-03-27 16:18:27 -05:00
|
|
|
super();
|
2019-03-26 17:04:44 -05:00
|
|
|
this.entityList = new EntityList();
|
2019-05-13 21:07:51 -05:00
|
|
|
this.index = -1;
|
2019-04-12 20:16:31 -05:00
|
|
|
this.tileGeometry = [];
|
2019-03-27 01:52:24 -05:00
|
|
|
this.tiles = new Tiles();
|
|
|
|
// Listeners.
|
2019-04-12 18:58:38 -05:00
|
|
|
this.entityList.on('entityAdded', this.onEntityAddedToLayer, this);
|
|
|
|
this.entityList.on('entityRemoved', this.onEntityRemovedFromLayer, this);
|
|
|
|
this.tiles.on('dataChanged', this.onTileDataChanged, this);
|
2019-04-12 20:16:31 -05:00
|
|
|
this.on('tilesetChanged', this.onTilesetChanged, this);
|
2019-04-12 18:58:38 -05:00
|
|
|
this.on('tilesetUriChanged', this.onTilesetUriChanged, this);
|
2019-04-12 20:16:31 -05:00
|
|
|
this.on('worldChanged', this.onWorldChanged, this);
|
2019-05-13 21:07:51 -05:00
|
|
|
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);
|
|
|
|
}
|
2019-03-27 01:52:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
addEntity(entity) {
|
|
|
|
this.entityList.addEntity(entity);
|
|
|
|
}
|
|
|
|
|
2019-04-12 20:16:31 -05:00
|
|
|
addTileGeometry() {
|
|
|
|
const tileset = this.tileset;
|
|
|
|
if (!tileset) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const world = this.world;
|
|
|
|
if (!world) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-04-13 03:40:13 -05:00
|
|
|
const halfTileSize = Vector.scale(tileset.tileSize, 0.5);
|
2019-04-12 20:16:31 -05:00
|
|
|
this.tiles.forEachTile((tile, x, y, i) => {
|
|
|
|
const shape = this.tileset.geometry(tile);
|
|
|
|
if (!shape) {
|
|
|
|
return;
|
|
|
|
}
|
2019-04-13 13:38:18 -05:00
|
|
|
shape.position = Vector.add(
|
2019-04-12 20:16:31 -05:00
|
|
|
halfTileSize,
|
|
|
|
Vector.mul([x, y], tileset.tileSize),
|
|
|
|
);
|
2019-04-16 13:41:29 -05:00
|
|
|
const body = world.createBody(shape);
|
|
|
|
body.static = true;
|
|
|
|
world.addBody(body);
|
|
|
|
this.tileGeometry.push(body);
|
2019-04-12 20:16:31 -05:00
|
|
|
});
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-28 22:33:20 -05:00
|
|
|
allEntities() {
|
|
|
|
return Array.from(this.entityList);
|
|
|
|
}
|
|
|
|
|
2019-03-27 01:52:24 -05:00
|
|
|
destroy() {
|
|
|
|
this.entityList.destroy();
|
|
|
|
this.entityList.off('entityAdded', this.onEntityAddedToLayer);
|
|
|
|
this.entityList.off('entityRemoved', this.onEntityRemovedFromLayer);
|
2019-04-12 18:49:07 -05:00
|
|
|
this.tiles.off('dataChanged', this.onTileDataChanged);
|
|
|
|
this.off('tilesetUriChanged', this.onTilesetUriChanged);
|
|
|
|
if (this.tileset) {
|
|
|
|
this.tileset.destroy();
|
|
|
|
}
|
2019-03-25 23:39:44 -05:00
|
|
|
}
|
|
|
|
|
2019-03-27 17:36:57 -05:00
|
|
|
findEntity(uuid) {
|
|
|
|
return this.entityList.findEntity(uuid);
|
|
|
|
}
|
|
|
|
|
2019-03-25 23:39:44 -05:00
|
|
|
fromJSON(json) {
|
2019-03-27 01:52:24 -05:00
|
|
|
if (json.entities) {
|
2019-05-16 23:01:57 -05:00
|
|
|
this.entityList.fromJSON(json.entities);
|
2019-03-27 01:52:24 -05:00
|
|
|
}
|
2019-03-25 23:39:44 -05:00
|
|
|
if (json.tiles) {
|
2019-03-27 01:52:24 -05:00
|
|
|
this.tiles.fromJSON(json.tiles)
|
2019-03-25 23:39:44 -05:00
|
|
|
}
|
|
|
|
if (json.tilesetUri) {
|
|
|
|
this.tilesetUri = json.tilesetUri;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-03-27 01:52:24 -05:00
|
|
|
onEntityAddedToLayer(entity) {
|
|
|
|
entity.layer = this;
|
|
|
|
this.emit('entityAdded', entity)
|
|
|
|
}
|
|
|
|
|
|
|
|
onEntityRemovedFromLayer(entity) {
|
|
|
|
this.emit('entityRemoved', entity);
|
|
|
|
}
|
|
|
|
|
2019-03-27 19:25:00 -05:00
|
|
|
onTileDataChanged() {
|
|
|
|
this.emit('tileDataChanged');
|
|
|
|
}
|
|
|
|
|
2019-04-12 20:16:31 -05:00
|
|
|
onTilesetChanged(oldTileset) {
|
|
|
|
let didChange = false;
|
|
|
|
if (oldTileset) {
|
|
|
|
this.removeTileGeometry();
|
|
|
|
didChange = true;
|
|
|
|
}
|
|
|
|
if (this.addTileGeometry()) {
|
|
|
|
didChange = true;
|
|
|
|
}
|
|
|
|
if (didChange) {
|
|
|
|
this.emit('tileGeometryChanged');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-12 18:49:07 -05:00
|
|
|
onTilesetUriChanged() {
|
|
|
|
if (!this.tilesetUri) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Tileset.load(this.tilesetUri).then((tileset) => {
|
|
|
|
this.tileset = tileset;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-04-12 20:16:31 -05:00
|
|
|
onWorldChanged(oldWorld) {
|
|
|
|
let didChange = false;
|
|
|
|
if (oldWorld) {
|
|
|
|
this.removeTileGeometry();
|
|
|
|
didChange = true;
|
|
|
|
}
|
|
|
|
if (this.addTileGeometry()) {
|
|
|
|
didChange = true;
|
|
|
|
}
|
|
|
|
if (didChange) {
|
|
|
|
this.emit('tileGeometryChanged');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-13 21:07:51 -05:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
return packets;
|
|
|
|
}
|
|
|
|
|
2019-03-27 01:52:24 -05:00
|
|
|
removeEntity(entity) {
|
|
|
|
this.entityList.removeEntity(entity);
|
|
|
|
}
|
|
|
|
|
2019-04-12 20:16:31 -05:00
|
|
|
removeTileGeometry() {
|
|
|
|
// ... tag geometry in world for removal?
|
|
|
|
}
|
|
|
|
|
2019-03-27 19:25:00 -05:00
|
|
|
setTileAt(x, y, tile) {
|
|
|
|
this.tiles.setTileAt(x, y, tile);
|
|
|
|
}
|
|
|
|
|
2019-05-08 21:28:47 -05:00
|
|
|
tick(elapsed) {
|
2019-05-13 21:07:51 -05:00
|
|
|
this.entityList.tick(elapsed);
|
|
|
|
}
|
|
|
|
|
|
|
|
toJSON() {
|
|
|
|
return {
|
|
|
|
tilesetUri: this.tilesetUri,
|
|
|
|
tiles: this.tiles.toJSON(),
|
|
|
|
};
|
2019-05-08 21:28:47 -05:00
|
|
|
}
|
|
|
|
|
2019-03-27 17:39:34 -05:00
|
|
|
visibleEntities(query) {
|
|
|
|
return this.entityList.visibleEntities(query);
|
|
|
|
}
|
|
|
|
|
2019-03-27 01:52:24 -05:00
|
|
|
}
|