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
System
class acts as a blueprint for all our game systems. It holds references to theEntityManager
, theScene
, and the specificComponent
classes it requires to function. - The
update
method iterates through all relevant entities and calls theprocessEntity
method for each one. - The
processEntity
method 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
.