Hi everyone!
Recently I've come to understand that having to download a game to play / test it is actually a major friction for a LOT of people. It even seems that less and less people around me own a PC and those who do often only have a PC from their company, on which they can't or don't want to download or install anything. Fair enough, it means it was time to get on with the "Web conversion" of my game. Now what I thought to be a walk in the park (given the relative simplicity of Bouncenoid) turned out to be much more annoying than anticipated - and for very different reasons I expected.
I guess it all starts with the dev framework you're using. In my case I started off with pygame and while this may be a good choice for simple games not necessarily meant to be shared/published widely, I'm starting to think that maybe right from the start I chose the wrong path... The good thing is that with pygame comes pygbag, which is a python package specially made to create a web version of pygame python games. And sure enough, after a few tweaks like adding "async def main()" to allow for asynchronous execution, Bouncenoid appeared in my browser... yet something seemed to be terribly bad:
- The soundtrack was horribly crackling
- Every screen felt sluggish like the browser was grinding almost to a halt, even for screens with hardly nothing going on.
- The game was virtually not playable as everything happened in slow motion.
What the hell? I mean I've seen games out there on browsers like super busy shooters with dozens of moving pieces, many meters going on, etc. and I could play fine. So how was this possible ?
Well, I have spent hours investigating to understand where the time was spent in the code and why it was costing so much resources when it played just fine on the desktop version. And it's not pretty.
The thing is that there is so much operations that we just take for granted on a desktop, especially display routines that we just assume would be the same inside a browser, but that's not the case - at least for me. And I'm not even talking about bits of the code where operations were done 60 times per second just to display a static image with no cache (yes, I know, I got it eventually). I'm talking about just displaying an image with some alpha or transparency. That turned out to be a huge cost for the browser when using the pygame functions, even with some caching going on. A blit with alpha can cost by itself 15 to 25 miliseconds, for a total budget of 16 ms to reach the 60 fps target. One of the reason is that the rendering with pygbag/Emscripten is done via SDL2 software, with no hardware acceleration.
Another point is that each python function call has a significant cost with the python interpreter compiled in WebAssembly (pyodide) compared to the native CPython. Some many "small" calls, like checking on a property 60 times per second for each brick when there can be 100+ bricks will cause the browser to sweat but is unseen on desktop.
I was expecting at first that calculating the physics, the collisions, etc. would be what could be costly. Not just displaying simple graphics.
Anyway, long story short, I spent a very long time working to get the game back to a level of performance that feels normal compared to the desktop version. Squeezing performance out of every part, caching as much as possible, pre-calculating things, etc. And eventually got there, but what a drag it was for something so simple visually.
Is it just me? Is it pygame ? Or is it the normal thing you have to get through when migrating from desktop to Web version ? I'm curious, really!