Not long ago, Clevyr was hired to write an interactive content creator for the web. This project would need to be able to create static images as well as videos out of simple elements like text and images. We had to have second-by-second control of what would be displayed on the screen and we would have to support animations of, and user interactions with, the displayed elements. Because of these requirements, we decided we would need to
A simple breakdown of ECS starts with the concept of entities (the E in ECS). At its core, an entity is just an object with a unique id that represents a single item or element. Each entity is given meaning by attaching components (the C in ECS) to it. Each component defines an adjective or group of adjectives. For example, a position component might contain X and Y coordinates. By attaching that position component to an entity, you give it those coordinates and therefore a position. But positions can change over time, and to change components or attach or remove them from entities, we use systems (the S in ECS). Systems analyse all the entities every game loop and perform any necessary changes. For example, if we attach a gravity component to an entity, it will start being pulled on the y-axis. A positioning system might check for the existence of a gravity component on every entity. If it has one, update the entity’s Y coordinate value in its position component. In this way, the entity will “fall” down the y-axis. This combination of entities, components, systems, and a game loop (or timer) makes up the basics of ECS.
Initially, we thought of using HTML canvas to display the various elements on screen. However, we realized that because most of our elements resemble simple HTML elements, if we used HTML and CSS instead of canvas, we could save a lot of time and effort. In addition, since we are rendering the rest of the application using ReactJS, we would be able to use ReactJS components as well.
So here is how the game system would be set up so far. The database would load up a list of entities with their associated components and feed them into the ECS. A timer based on requestAnimationFrame also needs to be loaded into the ECS. A visibility system would update an entity’s visible component based on the timer and the entity’s time component. Each entity has an element component to determine which HTML element / React component would be displayed to represent the entity. A position and size component would determine where and how large each element will be displayed. The question we came across at this point is how are we going to get React to properly render and update these entities?
Since we are using CSS, each component needs to be positioned absolutely and we use top, left, width, height, and visibility to position and size it. Whenever the ECS framework updates a value in an entity component, MobX will automatically detect it and tell React to re-render the appropriate display components. At this point, we now have a simple working game model, but there is one major thing missing. How are we going to update the ECS system from the rendered DOM?
My first implementation was to simply expose the list of entities to React and allow it to mutate any entities it wanted. Although this did work, it was a bad idea because we no longer had a one-way data flow that is ideal for complicated logic systems. Taking cues from frameworks like Flux and Redux, I added a concept of action components. These components are always added to new entities (action entities) that are then added directly to the ECS framework. The ECS systems can detect action components and mutate other entities in some way. Then, all the active components and their entities are purged at the end of each game loop. In this way, the ECS systems have full control over all entity and component manipulation. We no longer have to search the whole codebase to track down where entity mutations might be occurring.
Another benefit of the ECS-React approach is that it can easily be adapted to use SVG elements and even HTML canvas where needed. You just have to display those inside React and send any applicable information from ECS to them. For example, we used SVG elements to display rectangles and circles, but we also could have rendered a Canvas element and draw the shapes directly onto it.
Combining an ECS framework, ReactJS, and Mobx, we were able to build a very stable and flexible content creation system for our client. Soon, we are planning on open sourcing our ECS implementation to allow others to easily start experimenting with React powered games and game-like applications. Thanks for reading!
Jon White is a Senior Software Engineer of Clevyr, Inc. Clevyr makes software using all the buzzwords like AI, Machine Learning, Augmented Reality and Virtual Reality.
Schedule a Free Consultation with Clevyr today to discuss your software needs! https://clevyr.com/contact-us/