106 lines
3.7 KiB
JavaScript
106 lines
3.7 KiB
JavaScript
|
import { BaseEntity } from './entity';
|
||
|
import { EventBus } from '../event-bus';
|
||
|
import { Query } from './query';
|
||
|
import { System } from './system';
|
||
|
export class World {
|
||
|
constructor() {
|
||
|
this.nextEntityID = 0;
|
||
|
this.nextComponentID = 0;
|
||
|
this.nextQueryID = 0;
|
||
|
this.entities = new Array();
|
||
|
this.systems = new Set();
|
||
|
this.components = new Map();
|
||
|
this.componentNamesToIDs = new Map();
|
||
|
this.queryCache = new Array();
|
||
|
this.eventBus = new EventBus();
|
||
|
}
|
||
|
run() {
|
||
|
this.systems.forEach((system) => {
|
||
|
system.execute(this);
|
||
|
});
|
||
|
}
|
||
|
createSystem(systemExecutor) {
|
||
|
const newSystem = new System(systemExecutor);
|
||
|
this.systems.add(newSystem);
|
||
|
}
|
||
|
addSystem(system) {
|
||
|
this.systems.add(system);
|
||
|
}
|
||
|
addEntity(entity) {
|
||
|
this.entities.push(entity);
|
||
|
this.markQueriesDirty();
|
||
|
}
|
||
|
removeEntity(entityToRemove) {
|
||
|
this.entities = this.entities.filter((entity) => entity !== entityToRemove);
|
||
|
this.markQueriesDirty();
|
||
|
}
|
||
|
createEntity(components) {
|
||
|
const newEntity = new BaseEntity();
|
||
|
newEntity.id = this.nextEntityID;
|
||
|
this.nextEntityID++;
|
||
|
components.forEach((component) => {
|
||
|
if (this.componentNamesToIDs.has(component.name)) {
|
||
|
component.id = this.componentNamesToIDs.get(component.name);
|
||
|
}
|
||
|
else {
|
||
|
this.componentNamesToIDs.set(component.name, this.nextComponentID);
|
||
|
component.id = this.nextComponentID;
|
||
|
this.nextComponentID++;
|
||
|
}
|
||
|
newEntity.addComponent(component);
|
||
|
});
|
||
|
this.entities.push(newEntity);
|
||
|
this.markQueriesDirty();
|
||
|
return newEntity;
|
||
|
}
|
||
|
extendEntity(entity, components) {
|
||
|
const toClone = this.entities.find((found) => entity.name === found.constructor.name);
|
||
|
const cloned = new BaseEntity();
|
||
|
cloned.id = this.nextEntityID;
|
||
|
this.nextEntityID++;
|
||
|
toClone.components.forEach((component) => {
|
||
|
cloned.addComponent(this.components.get(component.id));
|
||
|
});
|
||
|
components.forEach((component) => {
|
||
|
if (this.componentNamesToIDs.has(component.name)) {
|
||
|
component.id = this.componentNamesToIDs.get(component.name);
|
||
|
}
|
||
|
else {
|
||
|
this.componentNamesToIDs.set(component.name, this.nextComponentID);
|
||
|
component.id = this.nextComponentID;
|
||
|
this.nextComponentID++;
|
||
|
}
|
||
|
cloned.addComponent(component);
|
||
|
});
|
||
|
this.entities.push(cloned);
|
||
|
return cloned;
|
||
|
}
|
||
|
createComponent(component) {
|
||
|
const newComponent = component;
|
||
|
newComponent.id = this.nextComponentID;
|
||
|
this.nextComponentID++;
|
||
|
this.components.set(newComponent.id, newComponent);
|
||
|
this.componentNamesToIDs.set(component.name, component.id);
|
||
|
return newComponent;
|
||
|
}
|
||
|
query(include, exclude) {
|
||
|
const query = new Query(include, exclude, this);
|
||
|
const cache = this.queryCache.find((item) => item.include == include && item.exclude == exclude);
|
||
|
if (cache) {
|
||
|
return cache.execute();
|
||
|
}
|
||
|
this.queryCache.push(query);
|
||
|
return query.execute();
|
||
|
}
|
||
|
createQuery(include, exclude) {
|
||
|
const newQuery = new Query(include, exclude, this);
|
||
|
newQuery.id = this.nextQueryID;
|
||
|
this.nextQueryID++;
|
||
|
this.queryCache.push(newQuery);
|
||
|
return newQuery;
|
||
|
}
|
||
|
markQueriesDirty() {
|
||
|
this.queryCache.forEach((query) => (query.isDirty = true));
|
||
|
}
|
||
|
}
|