I feel guilty for pushing ECS as the future of gameplay programming despite the fact I never created a game with it, mainly due to depending on mainstream current engines.
This weekend I wanted to do a small fun pico8 thing to try to learn more about ECS in practice.
Initially ECS looked attractive to me due to the potential of reaching that magical point when a system madeup of small highly specialized parts comes alive with complex behavior that would be difficult to write directly
[thread]

I started by implementing a small piece directly in pico8 in the way I'd do it if this was a gamejam, through this stage I experimented on creating isometric art by making a rapid model then rendering it from 8 isometric viewpoints then hand drawing 16x16 sprites in pico8 based on the renders. I used wings3d+povray to do these

Putting these isometric sprites together, the results were better than I expected! In a full project, I'd create some automation for rendering models from all required angles then creating initial sprites by scaling down the renders

Then I started reimplementing that from scratch using a minimal ECS framework that I developed partially for Love2D a while ago. Did you know pico8 lua lacks the table.* std library?
The lessons began immediately. I had to implement an init script that runs once which is trivial to do directly, but here I implemented it as a system (function) that runs on entities with "init" components killing the entity at the end. There was no way for me to control when the init system runs though..

Follow

But the first big thing of note is how slow i suddenly was at implementing every single new element. It took me an order of magnitude more time to get that same scene drawn and animated and I havent even done locomotion yet! It feels my brain doesn't yet know how to speak ECS, so things like having an isometric sprite with little spinny fans and an offset flickery shadow took much more careful thinking to get running.

Another thing I noticed: when I need something to behave slightly differently I have to fight the urge to expand existing components and instead create a new component for it.
Example: shadow is a sprite that draws every other frame, rather than add a flag to the sprite component to do that I created a new shadow-sprite that draws every other frame.
I'm not 100% sure this is a better approach, it just naturally evolved due to the lower cost of creating new components vs modifying existing code

That tendency to create new components led to an explosion in similar components that behave slightly differently: sprite, animated sprite, shadow sprite, isometric sprite, etc
And each type of sprite required a slightly modified drawing system/function.. suffice it to say, ECS so far has been very harsh on code density. I haven't even gotten locomotion to work yet and it's already half way through pico8's token limit! 😯

Next insight comes from the cycle of: create new component, init/spawn a test entity by throwing a mass of data into it, then implement new update/draw systems to finally see something.
Parts of that cycle are definitely hurt by the code-based pipeline. Initializing components would greatly benefit from being UI driven rather than be hardcoded in the source.
So perhaps an ideal ECS pipeline would offload as much as it can to UI and pure data and leave the coding for game systems exclusively 🤔

Picked my ECS experiment back up since I'm on break, struggled with implementing a collision system in ECS, my first attempt was an OOP knee-jerk reaction that didn't even work 🙊
Second time I stayed within ECS boundaries but tried to hack it together and it didn't work. I'm finding a curious property in working on gameplay systems in ECS: you can't half-ass it. It'll only work correctly when you properly implement it. This is possibly a great property compared to the god objects approach 🤔

So now I have a proper collision detection system running fully in ECS, I refactored some elements and to my surprise it seems that whenever I break a component into smaller ones, the result is cleaner code!
At this point the code is taking up 5370 tokens, I have a pretty complete barebones ECS system with some interesting properties, and I think I reached the magical point of things glued together just magically working 😎
I'm happy with what I learned so far and may take this further 😏

HoverECS final update: got a minimal gameloop going, passed 7000 pico8 tokens & almost all building blocks are re-usable. So new vehicles, enemies, buildings, etc should be construct-able using existing components in theory.
I consider this experiment done. The final challenge I had was scene management in pure ECS. Perhaps a balanced compromise is having a traditional scene manager where each scene runs its own ECS (map, battle, menu, etc).
Try the demo here: cloudmillgames.com/demos/hover

Sign in to participate in the conversation
Gamedev Mastodon

Mastodon server focused on game development and related topics.