assassin-bug/framework/ecs/index.js

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));
}
}