I'm trying to get a better feel for how an entity-component-system system works. I'm most comfortable in JavaScript, so that's what I wrote it in. I'm mostly looking for ways my code violates ECS principles, but am also looking for ways to make my code more idiomatic.
class Component {
get type() { return this.constructor.name; }
constructor(data) {
this.data = data;
}
}
class Entity {
get type() { return this.constructor.name; }
constructor(id) {
this.id = id;
this.components = [];
}
get(type) { return this.components.find(c => c.type === type); }
assign(component) {
const included = this.get(component.type);
if (included === undefined) this.components.push(component);
else this.components[this.components.indexOf(included)] = component;
}
}
class System {
get type() { return this.constructor.name; }
constructor(types, callback) {
this.types = types;
this.callback = callback;
}
run(entities) {
entities.forEach(e =>
this.types.every(t => e.get(t) !== undefined) &&
this.callback(e)
);
}
}
Also, here's a basic example of how the system gets extended.
class ErrorComponent extends Component {
constructor(error) {
super(error);
}
}
class ErrorSystem extends System {
constructor() {
super(
["ErrorComponent"],
e => console.error(e.get("ErrorComponent").data)
);
}
}
const testComponent = new ErrorComponent("test");
const testComponent2 = new ErrorComponent("test2");
const testEntity = new Entity("test");
testEntity.assign(testComponent);
testEntity.assign(testComponent2);
const entities = [testEntity];
const testSystem = new ErrorSystem();
testSystem.run(entities);
One other thing that I feel like I don't understand about ECS is why I should extend Component
and System
, but not Entity
. It feels asymmetrical. For example, could I say
class ErrorEntity extends Entity {
constructor(id, error) {
super(id);
this.assign(new ErrorComponent(error));
}
}
? Or does this violate some principle of ECS?