UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

228 lines • 8.09 kB
export type EntityManagerState = number; export namespace EntityManagerState { let Initial: number; let Starting: number; let Running: number; let Failed: number; let Stopping: number; let Stopped: number; } /** * Brings together {@link System}s and an {@link EntityComponentDataset} * Main entry point into the simulation process. * * @example * const em = new EntityManager() * * em.addSystem(new MySystem()) * em.addSystem(new MyOtherSystem()) * * em.attachDataset(new EntityComponentDataset()) * * em.startup(); * * // .. * * em.simulate(0.016); // advance simulation forward by 16ms * * // .. * * em.shutdown(); * * // .. * * em.detachDataset(); * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class EntityManager { /** * Registered systems * @readonly * @type {System[]} */ readonly systems: System<any, any, any, any, any>[]; /** * Current order of execution. * Note: this can be smaller that the number of registered systems, as systems are only added to the execution order once their startup finishes * @readonly * @private * @type {System[]} */ private readonly systemsExecutionOrder; /** * Observers associated with individual systems, responsible for {@link System.link}/{@link System.unlink} * @readonly * @private * @type {Map<System,EntityObserver>} */ private readonly systemObservers; /** * @readonly */ readonly on: { systemStarted: Signal<any, any, any, any, any, any, any, any>; systemStopped: Signal<any, any, any, any, any, any, any, any>; /** * @type {Signal<System>} */ systemAdded: Signal<System<any, any, any, any, any>>; systemRemoved: Signal<any, any, any, any, any, any, any, any>; }; /** * * @type {EntityManagerState} */ state: EntityManagerState; /** * Track remainders of simulation time for fixed step * Needed for accurate time keeping * @private * @readonly * @type {Map<System, number>} */ private readonly systemAccumulatedFixedStepTime; /** * Value used to execute {@link System.fixedUpdate} * In seconds. * The default is ~60 Hz, which should be sufficient for most use-cases. * Setting this value higher will reduce the total number of steps per second, and typically lead to better performance. * Setting this value lower will increase number of steps per second, increasing simulation accuracy at the cost of performance. * Make sure you understand the implications when modifying this. * A good safe range is [0.001 - 0.2] * @type {number} */ fixedUpdateStepSize: number; /** * How long can any given system run it's {@link System.fixedUpdate}, per simulation update * This is value allows us to avoid cases where {@link System.fixedUpdate} takes longer that its time step and causes a runaway freeze * In milliseconds. * @type {number} */ fixedUpdatePerSystemExecutionTimeLimit: number; /** * Currently attached dataset. * Do not modify directly, instead use {@link attachDataset} and {@link detachDataset} respectively. * @type {EntityComponentDataset} */ dataset: EntityComponentDataset; /** * Whenever a system is added or removed, optimal execution plan changes, this flag tells us to rebuild the current plan * see {@link #systemsExecutionOrder} * @type {boolean} * @private */ private __execution_order_needs_update; /** * Rebuild execution order * @private */ private updateExecutionOrder; /** * Get list of all components referenced by active systems * @returns {Class[]} */ getComponentTypeMap(): Class[]; /** * Link a given dataset, will cause associated systems to work with the new dataset as well * @param {EntityComponentDataset} dataset * @throws {Error} if another dataset is attached * @throws {Error} if dataset is incompatible with current system set */ attachDataset(dataset: EntityComponentDataset): void; /** * Dissociate currently bound dataset, will cause attached systems to unlink entities held in the dataset. * Idempotent, if no dataset is attached - nothing will happen. */ detachDataset(): void; /** * @template T * @param {Class<T>} systemClass * @returns {boolean} */ hasSystem<T>(systemClass: Class<T>): boolean; /** * @template T * @param {Class<T>} systemClass * @returns {T|null} */ getSystem<T_1>(systemClass: Class<T_1>): T_1; /** * @deprecated use {@link EntityComponentDataset.getComponentClassByName} instead * @template T * @param {string} className * @returns {null|Class<T>} */ getComponentClassByName<T_2>(className: string): null | Class<T_2>; /** * Advance simulation forward by a specified amount of time * @param {number} timeDelta in seconds */ simulate(timeDelta: number): void; /** * If the {@link EntityManager} is already started, the system will be started automatically before being added * @param {System} system * @returns {Promise} resolution depends on {@link EntityManager}'s state, if running - promise resolves after system startup. Otherwise, the promise will be resolved immediately. * @throws {IllegalStateException} */ addSystem(system: System<any, any, any, any, any>): Promise<any>; /** * * @param {System} system * @returns {Promise<boolean>} */ removeSystem(system: System<any, any, any, any, any>): Promise<boolean>; /** * @private * @param {System} system * @param {function(system: System)} successCallback * @param {function(reason:*)} errorCallback */ private stopSystem; /** * @private * @param {System} system * @param {function(system: System)} successCallback * @param {function(reason:*)} errorCallback */ private startSystem; /** * This method is asynchronous by nature, it has to wait for each system to finish its own startup. * Make sure to register callback to be notified when the startup has finished * @param {function} [readyCallback] executed once entity manager successfully completes startup * @param {function} [errorCallback] executed if entity manager encounters an error during startup */ startup(readyCallback?: Function, errorCallback?: Function): void; /** * * @param {Class} systemClass * @returns {Promise.<System>} */ promiseSystem(systemClass: Class): Promise<System<any, any, any, any, any>>; /** * @param {Class} SystemClass * @param {SystemState} state * @returns {Promise.<System>} */ promiseSystemInState(SystemClass: Class, state: SystemState): Promise<System<any, any, any, any, any>>; /** * This method is asynchronous by nature, it will not be done until each system has finished its shutdown * Make sure to use callback to be notified when the shutdown has completed * @param {function} [readyCallback] Called when shutdown finishes successfully. defaults to no-operation * @param {function} [errorCallback] Called when an error occurs during the shutdown process. defaults to console error output */ shutdown(readyCallback?: Function, errorCallback?: Function): void; /** * @deprecated use lowercase spelling `attachDataset` instead */ attachDataSet: (dataset: EntityComponentDataset) => void; /** * @deprecated use lowercase spelling `detachDataset` instead */ detachDataSet: () => void; } import { System } from "./System.js"; import Signal from "../../core/events/signal/Signal.js"; import { EntityComponentDataset } from "./EntityComponentDataset.js"; //# sourceMappingURL=EntityManager.d.ts.map