The benefits and drawbacks of ECS on low-spec hardware
February 12, 2022 • 5 minute read
I’ve been interested in programming with Lua for the PlayStation Portable for a while and I’ve been having lots of fun playing around with it and learning about its quirks. At the same time I’ve also been reading about data-oriented design in game development so I thought it’d be fun to give a shot at programming a simple demo using the ECS architectural pattern and see how it compared to a traditional object-oriented programming approach. Last year I put together this very barebones ECS boilerplate for OneLua, a multi-platform Lua interpreter, which I never actually used for anything so I thought that this would be the perfect time to give it a go.
ECS in a nutshell
As I understand it, the basic premise of ECS is the concept of decoupling data and logic between components and systems instead of having both as part of the same object. With that in mind, here’s an oversimplification of how I see it:
- Components are sets of raw data. A practical example is the handling of positions: there’s a position component which is comprised of x and y coordinates. This component can then be reused by every entity that has a position in the world.
- Entities are simply groups of different components. Neither entities nor components have methods, because logic runs separately on systems.
- Systems operate on data present on components. Say you have a movement system; it should only operate on entities that have position (x, y) and movement (direction, speed) components.
- Worlds are the upmost level data structures that basically divide the game in different stages. They work like regular game states would, with their own load, free, update, and draw methods with the added abilities to register and unregister systems and add or remove entities. Worlds are effectively the part where everything is glued together.
With the explanation above here’s a demonstration and how all the entities, components and systems were structured:
The demo running on PPSSPP v1.9.3
The ECS structure
So, how does it fare against OOP on low-spec hardware?
From a development standpoint, as opposed to using OOP and dealing with the spaghetti that usually comes with it, I find ECS way more intuitive and enjoyable to make games with. I really like the way everything is reusable, iterable and easier to debug. FPS drops unexpectedly when there are many enemies on screen? Comment out the rendering system and see if it makes a difference! It’s a breeze and most of the times I did run into problems, it was me who had mistakenly passed a parameter onto a component or who had forgotten to add components to the respective entities.
But nothing is without its drawbacks and in this case, what I get in development time and ease-of-use, it’s taken from me in performance. Don’t get me wrong, it works quite well so far as the PSP, which is pretty low-spec by today’s standards, has been able to process everything detailed above, keeping a steady frame-rate of 60 frames per second as long as the number of active enemies is below 30 and the number of active bullets is below 25. By the time I reach 750 collision detection calculations per frame though, the frame-rate is easily dropping 15-20 frames, even before I implemented proper sprite rendering, animation, sound and other important systems that are usually part of games.
This happens because the more systems I add into the game, the more processing has to be done on every run of the loop. While it could certainly be further optimized, this overhead is expected, as all that background work that keeps the ECS framework going are running on Lua, layers above the actual hardware. I’m assuming that taking advantage of lower-level languages like C to implement the framework, handling memory allocation properly and providing bindings to use in Lua would benefit its performance, but that is behind the scope of my knowledge on the topic at the moment.
As a test I tried to get the same project up and running following a more straightforward object-oriented approach and, as expected, there was an actual gain in performance: pumping the number of active bullets up to 30 and the number of enemies up to 50, literally doubling collision checks, had no hit in performance and the PSP was able to keep a steady 60 FPS frame-rate.
Final thoughts
I definitely enjoyed playing around with DOD and learning how it differs from OOP. I can safely say that while I’ll definitely keep using ECS on my games that run on current-gen hardware, I’ll probably think twice when it comes to older hardware.