Core components
Entity component system
System
20 min
overview systems are the logic processors in the ir engine's entity component system (ecs) they contain the algorithms and behaviors that operate on entities based on the components they possess while entities provide identity and components store data, systems implement the actual functionality that makes applications dynamic and interactive systems typically query for entities with specific component combinations, process their data according to game rules or application logic, and update component values accordingly this separation of logic from data is a key principle of the ecs architecture, enabling modular, maintainable, and performant code core concepts system purpose systems serve several essential purposes in the ecs architecture logic implementation they contain the algorithms and behaviors that drive application functionality entity processing they operate on groups of entities that match specific component criteria component manipulation they read and modify component data to implement behaviors state management they control how the application state evolves over time event handling they respond to inputs, triggers, and other events by focusing solely on logic and behavior, systems maintain a clear separation of concerns within the ecs architecture system structure a typical system consists of several key elements query a specification of which entities the system should process, based on component requirements execute function the logic that runs when the system is invoked, typically once per frame or update cycle identifier a unique name or id that distinguishes the system from others execution order configuration that determines when the system runs relative to other systems this structure allows systems to focus on specific aspects of application behavior while coordinating with other systems implementation defining queries before creating a system, you typically define a query that specifies which entities the system should process // import the necessary functions import { definequery } from '@ir engine/ecs'; // assume positioncomponent and velocitycomponent are already defined // define a query for entities with both position and velocity components const movableentitiesquery = definequery(\[ positioncomponent, velocitycomponent ]); the definequery function takes an array of component types that entities must possess returns a function that, when called, returns the current list of matching entities efficiently tracks entities as components are added or removed queries can be more complex, including required components (entities must have these) optional components (entities may have these) excluded components (entities must not have these) creating systems systems are defined using the definesystem function, which registers a new system with the ecs // import the necessary functions import { definesystem, getcomponent } from '@ir engine/ecs'; // assume movableentitiesquery is defined as above // define a movement system const movementsystem = definesystem({ // unique identifier for the system uuid 'game movementsystem', // logic to execute when the system runs execute () => { // get all entities matching our query const entities = movableentitiesquery(); // process each entity for (const entity of entities) { // get the entity's components const position = getcomponent(entity, positioncomponent); const velocity = getcomponent(entity, velocitycomponent); // update position based on velocity position x += velocity dx; position y += velocity dy; } }, // configuration for system execution order insert { after \['game inputsystem'], before \['game collisionsystem'] } }); the definesystem function takes a configuration object with a unique id, execute function, and insertion details registers the system with the ecs engine returns a reference to the system for later use the execute function is the heart of the system, containing the logic that processes entities and updates their components system execution flow when a system runs, it typically follows this sequence sequencediagram participant engine as ecs engine participant system as system participant query as entity query participant components as component storage engine >>system call execute() system >>query get matching entities query >>system return entity list \[1, 5, 8] loop for each entity system >>components get component data components >>system return component values system >>system process data (apply logic) system >>components update component values end system >>engine execution complete this flow ensures that the system only processes entities that match its criteria component data is accessed efficiently updates are applied consistently system execution order systems can specify their execution order relative to other systems // define a system with explicit ordering const physicssystem = definesystem({ uuid 'game physicssystem', execute () => { // physics simulation logic }, insert { after \['game inputsystem'], // run after input is processed before \['game rendersystem'], // run before rendering fixedupdate true // run at a fixed time step } }); the insert configuration allows systems to specify which systems should run before this one ( after ) which systems should run after this one ( before ) whether the system requires a fixed update rate ( fixedupdate ) this ordering ensures that dependencies between systems are respected and that operations occur in the correct sequence system types and patterns different types of systems serve different purposes in an application processing systems these systems iterate through entities and update their components // a typical processing system 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; } } }); processing systems are the most common type, handling regular updates to entity state event systems these systems respond to specific events or inputs // an event handling system const inputsystem = definesystem({ uuid 'game inputsystem', execute () => { const entities = playercontrolledquery(); // check for input events if (iskeypressed('arrowright')) { for (const entity of entities) { const velocity = getcomponent(entity, velocitycomponent); velocity dx = 5; // move right } } else if (iskeypressed('arrowleft')) { for (const entity of entities) { const velocity = getcomponent(entity, velocitycomponent); velocity dx = 5; // move left } } else { for (const entity of entities) { const velocity = getcomponent(entity, velocitycomponent); velocity dx = 0; // stop horizontal movement } } } }); event systems translate external inputs or triggers into component state changes lifecycle systems these systems manage entity creation, initialization, and destruction // a system that spawns enemies const enemyspawnsystem = definesystem({ uuid 'game enemyspawnsystem', execute () => { const timecomponent = getcomponent(globalentity, timecomponent); // spawn a new enemy every 5 seconds if (timecomponent elapsed % 5 < 0 016) { // assuming 60 fps const enemyentity = createentity(); // initialize with required components setcomponent(enemyentity, positioncomponent, { x math random() 800, y 0 }); setcomponent(enemyentity, velocitycomponent, { dx 0, dy 2 }); setcomponent(enemyentity, enemycomponent, { health 100, type 'basic' }); } } }); lifecycle systems ensure that entities are created, configured, and removed appropriately practical examples game physics system a system that implements basic physics for game objects // define queries for physics processing const physicsbodyquery = definequery(\[ positioncomponent, velocitycomponent, physicsbodycomponent ]); const gravityaffectedquery = definequery(\[ velocitycomponent, gravityaffectedcomponent ]); // define the physics system const physicssystem = definesystem({ uuid 'game physicssystem', execute (deltatime) => { // apply gravity to affected entities const gravityentities = gravityaffectedquery(); for (const entity of gravityentities) { const velocity = getcomponent(entity, velocitycomponent); velocity dy += 9 8 deltatime; // apply gravity } // update positions based on velocity const physicsentities = physicsbodyquery(); for (const entity of physicsentities) { const position = getcomponent(entity, positioncomponent); const velocity = getcomponent(entity, velocitycomponent); const body = getcomponent(entity, physicsbodycomponent); // apply velocity with drag position x += velocity dx deltatime; position y += velocity dy deltatime; // apply drag velocity dx = (1 body drag deltatime); velocity dy = (1 body drag deltatime); } }, insert { fixedupdate true // physics typically runs at a fixed time step } }); this system demonstrates how physics behavior can be implemented by processing entities with the appropriate components collision detection system a system that checks for collisions between entities // define a query for collidable entities const collidablequery = definequery(\[ positioncomponent, collidercomponent ]); // define the collision system const collisionsystem = definesystem({ uuid 'game collisionsystem', execute () => { const entities = collidablequery(); // check each entity against all others for (let i = 0; i < entities length; i++) { const entitya = entities\[i]; const posa = getcomponent(entitya, positioncomponent); const collidera = getcomponent(entitya, collidercomponent); for (let j = i + 1; j < entities length; j++) { const entityb = entities\[j]; const posb = getcomponent(entityb, positioncomponent); const colliderb = getcomponent(entityb, collidercomponent); // simple circle collision check const dx = posa x posb x; const dy = posa y posb y; const distance = math sqrt(dx dx + dy dy); const mindistance = collidera radius + colliderb radius; if (distance < mindistance) { // collision detected! // add collision response or trigger events setcomponent(entitya, collisioneventcomponent, { collidedwith entityb }); setcomponent(entityb, collisioneventcomponent, { collidedwith entitya }); } } } }, insert { after \['game physicssystem'], before \['game collisionresponsesystem'] } }); this system shows how to implement interaction between entities by checking for spatial relationships benefits of systems the system based approach provides several key advantages separation of concerns systems focus on specific behaviors, making code more modular and maintainable performance optimization systems can process entities in batches, taking advantage of cache locality flexibility new behaviors can be added by creating new systems without modifying existing code testability systems can be tested in isolation with mock entities and components scalability systems can be parallelized to take advantage of multi core processors these benefits make systems a powerful tool for implementing complex application logic next steps while systems provide the logic for processing entities and components, they need to be managed and coordinated by a central authority the next chapter explores the engine or world that orchestrates the entire ecs next engine (world) docid\ r col hvok yk6dm6jdd3