Creating a Base System Class in an ECS Architecture
The final piece of the puzzle is creating systems. These systems will query for entities with specific components and implement the game logic. For example, a MovementSystem will look for entities with a MovementComponent and update their positions each frame.
Let's establish a foundation for all our future game systems. We'll create a base System class that other systems can inherit from. This goes a long way towards ECS goal of having a common interface for all code.
// System.ts
import { Entity, EntityManager } from "./Entity";
import { Component } from "./Component";
import { Scene } from "@babylonjs/core";
export abstract class System {
protected entities: Entity[] = [];
protected componentClasses: Component[];
protected scene: Scene;
protected entityManager: EntityManager;
constructor(
entityManager: EntityManager,
componentClasses: ComponentClass[],
) {
this.entityManager = entityManager;
if (!entityManager.entities) {
console.error("EntityManager has no entities");
return;
}
const entities = entityManager.entities.values();
this.scene = entityManager.scene;
this.componentClasses = componentClasses;
for (const entity of entities) {
const gotEmAll = this.componentClasses.every((componentClass) => {
return entity.hasComponent(componentClass);
});
if (gotEmAll) this.entities.push(entity);
}
}
// Updates each entity this system is concerned with
update(deltaTime: number): void {
this.entities.forEach((entity: Entity) => {
this.processEntity(entity, deltaTime);
});
}
// Abstract method to process each entity. This should be implemented by subclasses.
protected abstract processEntity(entity: Entity, deltaTime: number): void;
}
Explanation:
- This
Systemclass acts as a blueprint for all our game systems. It holds references to theEntityManager, theScene, and the specificComponentclasses it requires to function. - The
updatemethod iterates through all relevant entities and calls theprocessEntitymethod for each one. - The
processEntitymethod is abstract, meaning it must be implemented by concrete system classes that inherit fromSystem.
In Sum
We've laid the groundwork for our ECS architecture. We have entities, components, and systems. The next step is to create concrete systems that implement the game logic. We'll start with a MovementSystem that updates the position of entities with a MovementComponent.