import * as I from 'immutable'; import {compose} from '@avocado/core'; import {create as createEntity, EntityList} from '@avocado/entity'; import {EventEmitter, Property} from '@avocado/mixins'; import {StateSynchronizer} from '@avocado/state'; import {Tiles} from './tiles'; const decorate = compose( EventEmitter, Property('tilesetUri', { track: true, }), ); export class Layer extends decorate(class {}) { constructor() { super(); this.entityList = new EntityList(); this._state = I.Map(); this.tiles = new Tiles(); // Listeners. this.onEntityAddedToLayer = this.onEntityAddedToLayer.bind(this); this.onEntityRemovedFromLayer = this.onEntityRemovedFromLayer.bind(this); this.entityList.on('entityAdded', this.onEntityAddedToLayer); this.entityList.on('entityRemoved', this.onEntityRemovedFromLayer); this.onTileDataChanged = this.onTileDataChanged.bind(this); this.tiles.on('dataChanged', this.onTileDataChanged); } addEntity(entity) { this.entityList.addEntity(entity); } destroy() { this.entityList.destroy(); this.entityList.off('entityAdded', this.onEntityAddedToLayer); this.entityList.off('entityRemoved', this.onEntityRemovedFromLayer); } findEntity(uuid) { return this.entityList.findEntity(uuid); } fromJSON(json) { if (json.entities) { json.entities.forEach((entityJSON) => { const entity = createEntity(); this.entityList.addEntity(entity.fromJSON(entityJSON)); }); } if (json.tiles) { this.tiles.fromJSON(json.tiles) } if (json.tilesetUri) { this.tilesetUri = json.tilesetUri; } return this; } onEntityAddedToLayer(entity) { entity.addTrait('layered'); entity.layer = this; this.emit('entityAdded', entity) } onEntityRemovedFromLayer(entity) { if (entity.is('layered')) { entity.removeTrait('layered'); } this.emit('entityRemoved', entity); } onTileDataChanged() { this.emit('tileDataChanged'); } removeEntity(entity) { this.entityList.removeEntity(entity); } patchState(patch) { for (const step of patch) { const {op, path, value} = step; if ('/' === path) { if (value.entityList) { this.entityList.patchState([ { op: 'replace', path: '/', value: value.entityList } ]); } if (value.tilesetUri) { this.tilesetUri = value.tilesetUri; } if (value.tiles) { this.tiles.patchState([ { op: 'replace', path: '/', value: value.tiles } ]); } } else { const [key, substep] = StateSynchronizer.forwardStep(step); if ('entityList' === key) { this.entityList.patchState([substep]); } if ('tiles' === key) { this.tiles.patchState([substep]); } } } } setTileAt(x, y, tile) { this.tiles.setTileAt(x, y, tile); } get state() { return this._state; } tick(elapsed) { if (this.entityList) { this.entityList.tick(elapsed); this._state = this._state.set('entityList', this.entityList.state); } this._state = this._state.set('tilesetUri', this.tilesetUri); this.tiles.tick(elapsed); this._state = this._state.set('tiles', this.tiles.state); } visibleEntities(query) { return this.entityList.visibleEntities(query); } }