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