Core components
Entity component system
Engine (world)
24 min
overview the engine, often referred to as the world in ecs terminology, is the central coordinator of the ir engine's entity component system it serves as the container for all entities, components, and systems, providing the context in which they operate the engine manages entity creation and destruction, stores component data, orchestrates system execution, and maintains the application's main loop by centralizing these responsibilities, the engine ensures that all parts of the ecs work together coherently, creating a unified environment for game or application logic this chapter explores the concept, structure, and implementation of the engine within the ir engine core concepts engine purpose the engine serves several essential purposes in the ecs architecture central repository it maintains a comprehensive store of all entities and their component data entity management it handles the creation, tracking, and destruction of entities component storage it provides efficient storage and retrieval mechanisms for component data system orchestration it manages the execution of systems in the correct order and frequency application loop it drives the main update cycle that keeps the application running by fulfilling these roles, the engine acts as the foundation upon which the entire ecs architecture operates engine responsibilities the engine's responsibilities can be broken down into several key areas entity management creating new entities with unique identifiers tracking which entities exist in the world destroying entities when they are no longer needed recycling entity ids for efficiency component storage allocating memory for component data associating component data with specific entities providing access to component data through queries managing component addition and removal system execution maintaining a registry of available systems determining the execution order of systems invoking system execution at appropriate times providing systems with access to relevant entities and components application loop tracking time and calculating delta time between frames processing input events updating game state through system execution triggering rendering and output implementation engine initialization the engine is typically initialized at application startup // simplified from src/engine ts import as bitecs from 'bitecs'; import { createhyperstore, hyperstore } from '@ir engine/hyperflux'; export class engine { static instance engine; store hyperstore; constructor() { // initialize internal state } } export function createengine() engine { if (engine instance) { throw new error('engine already created!'); } // create the singleton instance engine instance = new engine(); // create the world/store using bitecs and hyperflux const world = bitecs createworld(createhyperstore()); engine instance store = world as hyperstore; // perform additional initialization console log("ir engine initialized"); return engine instance; } the createengine function creates a singleton instance of the engine class initializes the underlying ecs world using bitecs createworld enhances it with hyperflux state management capabilities returns the initialized engine instance the resulting engine instance store (often also accessible as hyperflux store ) serves as the central repository for all ecs data system execution the engine orchestrates the execution of systems through a dedicated function // simplified from src/enginefunctions ts import { defaultsystempipeline } from ' /systemgroups'; import { executesystem } from ' /systemfunctions'; import { ecsstate } from ' /ecsstate'; export function executesystems(deltatime number) void { // update engine time tracking const ecsstate = ecsstate get(); ecsstate deltaseconds = deltatime; ecsstate elapsedseconds += deltatime; // execute all systems in the pipeline for (const systemorgroupuuid of defaultsystempipeline) { executesystem(systemorgroupuuid); } // update performance metrics ecsstate lastsystemexecutiontime = performance now() ecsstate framestarttime; } the executesystems function updates time related state (delta time, elapsed time) iterates through a predefined pipeline of systems executes each system or system group in order tracks performance metrics for monitoring the defaultsystempipeline typically organizes systems into logical groups like input processing, simulation, and rendering, ensuring they execute in the correct sequence application loop the engine drives the main application loop // simplified concept import { executesystems } from ' /enginefunctions'; function gameloop(timestamp number) void { // calculate time since last frame const deltatime = (timestamp lasttimestamp) / 1000; // convert to seconds lasttimestamp = timestamp; // process input events processinputevents(); // update game state by executing systems executesystems(deltatime); // render the current state renderframe(); // schedule the next frame requestanimationframe(gameloop); } // start the game loop let lasttimestamp = performance now(); requestanimationframe(gameloop); this loop calculates the time elapsed since the last frame processes any pending input events updates the game state by executing all systems renders the current state to the screen schedules the next iteration of the loop this continuous cycle drives the entire application, typically running at 60 frames per second or higher system groups and execution order systems are organized into groups to manage execution order // simplified from src/systemgroups ts export const inputsystemgroup = 'ir engine inputsystemgroup'; export const simulationsystemgroup = 'ir engine simulationsystemgroup'; export const physicssystemgroup = 'ir engine physicssystemgroup'; export const rendersystemgroup = 'ir engine rendersystemgroup'; // define the default execution pipeline export const defaultsystempipeline = \[ inputsystemgroup, simulationsystemgroup, physicssystemgroup, rendersystemgroup ]; systems can specify their position within these groups using the insert configuration // example system with explicit ordering const movementsystem = definesystem({ uuid 'game movementsystem', execute () => { // movement logic }, insert { after \['game inputsystem'], before \['game collisionsystem'], group simulationsystemgroup } }); this configuration ensures that systems execute in a logical order, with dependencies properly respected engine workflow the engine coordinates the flow of data and execution throughout the ecs sequencediagram participant app as application participant engine as engine/world participant entitymgr as entity manager participant compstore as component storage participant sysmgr as system manager app >>engine createengine() engine >>entitymgr initialize engine >>compstore initialize engine >>sysmgr initialize engine >>app engine ready app >>engine start game loop loop each frame engine >>engine calculate deltatime engine >>sysmgr executesystems(deltatime) sysmgr >>sysmgr get inputsystem sysmgr >>compstore query for input entities compstore >>sysmgr input entities sysmgr >>sysmgr execute inputsystem sysmgr >>sysmgr get movementsystem sysmgr >>compstore query for movable entities compstore >>sysmgr movable entities sysmgr >>sysmgr execute movementsystem sysmgr >>sysmgr get rendersystem sysmgr >>compstore query for renderable entities compstore >>sysmgr renderable entities sysmgr >>sysmgr execute rendersystem sysmgr >>engine systems executed engine >>app frame complete end this workflow illustrates how the engine initializes all ecs subsystems the game loop drives continuous updates systems query for relevant entities component data flows between storage and systems the process repeats for each frame engine internals under the hood, the engine leverages specialized libraries and data structures bitecs integration the ir engine often uses bitecs , a high performance ecs library, for core functionality // simplified concept import as bitecs from 'bitecs'; // create the world const world = bitecs createworld(); // create an entity const entity = bitecs addentity(world); // define a component (simplified) const positioncomponent = bitecs definecomponent(world, { x bitecs types f32, y bitecs types f32 }); // set component data bitecs addcomponent(world, positioncomponent, entity); positioncomponent x\[entity] = 10; positioncomponent y\[entity] = 20; // query for entities const query = bitecs definequery(\[positioncomponent]); const entities = query(world); the bitecs library provides highly optimized implementations of ecs concepts, using typed arrays and efficient memory layouts for performance hyperflux integration the ir engine enhances the basic ecs with hyperflux for advanced state management // simplified concept import { createhyperstore, hyperstore } from '@ir engine/hyperflux'; // create a hyperflux store const store = createhyperstore(); // create a world with hyperflux integration const world = bitecs createworld(store); // access the store for state management const gamestate = store state game; gamestate score set(100); this integration allows the engine to manage both ecs data and application state in a unified way practical examples complete game initialization a typical game initialization using the engine might look like // initialize the engine const engine = createengine(); // define components const positioncomponent = definecomponent({ name 'positioncomponent', schema s object({ x s number({ default 0 }), y s number({ default 0 }) }) }); const velocitycomponent = definecomponent({ name 'velocitycomponent', schema s object({ dx s number({ default 0 }), dy s number({ default 0 }) }) }); // define systems const movementsystem = definesystem({ uuid 'game movementsystem', execute () => { const entities = movableentitiesquery(); for (const entity of entities) { const position = getcomponent(entity, positioncomponent); const velocity = getcomponent(entity, velocitycomponent); position x += velocity dx; position y += velocity dy; } } }); // create initial entities const playerentity = createentity(); setcomponent(playerentity, positioncomponent, { x 100, y 100 }); setcomponent(playerentity, velocitycomponent, { dx 0, dy 0 }); // start the game loop startgameloop(); this example shows how the engine provides the foundation for defining components, systems, and entities, and then orchestrates their interaction through the game loop system dependencies and ordering the engine manages complex system dependencies // define systems with explicit ordering const inputsystem = definesystem({ uuid 'game inputsystem', execute () => { // process input and update player velocity }, insert { group inputsystemgroup } }); const physicssystem = definesystem({ uuid 'game physicssystem', execute () => { // apply physics simulation }, insert { after \['game inputsystem'], group simulationsystemgroup } }); const collisionsystem = definesystem({ uuid 'game collisionsystem', execute () => { // detect and resolve collisions }, insert { after \['game physicssystem'], group simulationsystemgroup } }); const rendersystem = definesystem({ uuid 'game rendersystem', execute () => { // render game objects }, insert { after \['game collisionsystem'], group rendersystemgroup } }); the engine ensures these systems execute in the correct order, respecting both explicit dependencies and group assignments benefits of the engine the engine centered approach provides several key advantages centralized management all ecs components are coordinated through a single point of control consistent execution systems run in a predictable order with proper timing efficient data access the engine optimizes component storage and retrieval simplified api developers interact with a unified interface rather than separate subsystems performance optimization the engine can implement specialized optimizations for different platforms these benefits make the engine a critical component of the ecs architecture, providing the foundation that enables all other parts to work together effectively next steps with an understanding of how the engine coordinates entities, components, and systems, the next chapter explores how component data is structured and defined through component schemas next component schema docid\ bviluktf76s5iifqwxob4