An Entity Component System in Javascript

Taking advantage of my Christmas holidays, one topic I had pending exploring was the Entity component system (ECS) architecture pattern. It is used primarily in video-games, but it is fascinating because of the radical departure from object inheritance, heavily leaning into object composition instead.

One of the best ways to learn is to a) read and then b) experiment, so I went and built a minimal (but representative) vanilla Javascript ECS implementation.

For the impatient, the code is available here: https://github.com/Kartones/ecs, and a basic HTML demo is here: https://kartones.net/demos/028/.

I'll remark on a few technical details, but if you want to see how everything fits, the code is compact and easy to read.

I created three systems:

  • InputSystem: To handle (keyboard) input. It interacts with PositionComponent components, by modifying their velocity "vectors" and/or changing positions when the Spacebar is pressed (resets all entities to new random positions).
  • MovementSystem: Updates PositionComponent components movement logic: update position based on velocity, or stop if at a boundary (edge)
  • RenderSystem: Initializes the screen (an HTML canvas) and tells RenderComponent components to render based on their PositionComponent values.

As you might have noticed, there are two components:

  • PositionComponent: Keeps (x,y) and a velocity vector
  • RenderComponent: Keeps the "sprite" data

And finally, a few managers:

  • EntityManager: Entities do not exist as a class; they are mere identifiers. The sole purpose of EntityManager is to generate the entity IDs and keep track of them
  • ComponentManager: Keeps track of all components of each entity. When a system is going through an update sweep, queries this manager to ask for all components required; e.g., the RenderSystem asks for PositionComponent and RenderComponent, ensuring that any entity has both (or will be skipped)
  • SystemManager: A simple list of all configured systems, plus an update() method that, surprise, triggers an update cycle on all systems

And that is mostly everything! At first, I tried to plug in Phaser for rendering graphics and handling input, but it is already an ECS! So, instead of doing weird code to access some of the systems, I discarded it and implemented a simple keyDown handler for the input and an HTML canvas for the renderer. Still, Phaser looks so nice and well-structured, that I'll try it as a complete game engine in the future.

Tags: Development Game Dev

An Entity Component System in Javascript published @ . Author: