118 lines
2.7 KiB
JavaScript
118 lines
2.7 KiB
JavaScript
import * as I from 'immutable';
|
|
import mapValues from 'lodash.mapvalues';
|
|
|
|
import {arrayUnique, compose} from '@avocado/core';
|
|
import {QuadTree, Rectangle, Vector} from '@avocado/math';
|
|
import {EventEmitter} from '@avocado/mixins';
|
|
import {Synchronized} from '@avocado/state';
|
|
|
|
import {create} from './index';
|
|
|
|
const decorate = compose(
|
|
EventEmitter,
|
|
);
|
|
|
|
export class EntityList extends decorate(Synchronized) {
|
|
|
|
constructor() {
|
|
super();
|
|
this._entities = {};
|
|
this._quadTree = new QuadTree();
|
|
this._uuidMap = {};
|
|
}
|
|
|
|
*[Symbol.iterator]() {
|
|
for (const uuid in this._entities) {
|
|
const entity = this._entities[uuid];
|
|
yield entity;
|
|
}
|
|
}
|
|
|
|
addEntity(entity) {
|
|
const uuid = entity.instanceUuid;
|
|
this._entities[uuid] = entity;
|
|
this.state = this.state.set(uuid, entity.state);
|
|
entity.addTrait('listed');
|
|
entity.list = this;
|
|
entity.once('destroyed', () => {
|
|
this.removeEntity(entity);
|
|
});
|
|
this.emit('entityAdded', entity);
|
|
}
|
|
|
|
destroy() {
|
|
for (const entity of this) {
|
|
entity.destroy();
|
|
}
|
|
}
|
|
|
|
findEntity(uuid) {
|
|
if (this._uuidMap[uuid]) {
|
|
return this._entities[this._uuidMap[uuid]];
|
|
}
|
|
if (this._entities[uuid]) {
|
|
return this._entities[uuid];
|
|
}
|
|
}
|
|
|
|
patchStateStep(uuid, step) {
|
|
const localUuid = this._uuidMap[uuid];
|
|
const entity = this._entities[localUuid];
|
|
if (entity) {
|
|
if ('remove' === step.op) {
|
|
// Entity removed.
|
|
this.removeEntity(entity);
|
|
}
|
|
else {
|
|
// Exists; patch.
|
|
entity.patchState([step]);
|
|
}
|
|
}
|
|
else {
|
|
// New entity. Create with patch as traits.
|
|
const newEntity = create().fromJSON({
|
|
traits: step.value,
|
|
});
|
|
this._uuidMap[uuid] = newEntity.instanceUuid;
|
|
this.addEntity(newEntity);
|
|
}
|
|
}
|
|
|
|
get quadTree() {
|
|
return this._quadTree;
|
|
}
|
|
|
|
removeEntity(entity) {
|
|
const uuid = entity.instanceUuid;
|
|
delete this._entities[uuid];
|
|
this.state = this.state.delete(uuid);
|
|
this.emit('entityRemoved', entity);
|
|
if (entity.is('listed')) {
|
|
entity.removeTrait('listed');
|
|
}
|
|
}
|
|
|
|
tick(elapsed) {
|
|
for (const uuid in this._entities) {
|
|
const entity = this._entities[uuid];
|
|
entity.tick(elapsed);
|
|
}
|
|
this.state = this.state.withMutations((state) => {
|
|
for (const uuid in this._entities) {
|
|
const entity = this._entities[uuid];
|
|
state.set(uuid, entity.state);
|
|
}
|
|
});
|
|
}
|
|
|
|
visibleEntities(query) {
|
|
const quadTree = this._quadTree;
|
|
const entities = quadTree.search(query).map((node) => {
|
|
return node.data[2];
|
|
});
|
|
// Hitting multiple points for each entity can return duplicates.
|
|
return arrayUnique(entities);
|
|
}
|
|
|
|
}
|