Revisiting 12 Years Old Code: That Word Game
The Context
I made That Word Game in 2008, as a Flash game. It was my second game, following Ninjas!, still learning the rope of the programming language and trying to build a game library.
It was originally coded in Haxe and it used a physics engine called Physaxe, which was written by the author of Haxe. Although, at that time, Box 2D was already ported to Actionscript, my hang of Haxe was not very tight and I didn’t feel confident to undertake such a port. Physaxe did its job though and, because of the power horse that Flash was, it worked quite fast, given the complexity and the amount of the collision shapes.
The Problem
In 2018, I’ve undertake a huge task to port all my Haxe/Flash games to HTML5, using OpenFL. That Word Game was among them and the port was verbatim, without any optimization specific to the platform it ran on (Javascript/HTML5).
As soon as I made the port, I’ve realized that frame rate is, well…bad. It didn’t even come near the Flash version and, it was generally unplayable. I’ve tried to delve into the inner workings of Physaxe and optimize it a little bit, as well as tweaking the simulation to favor speed over precision, but even the final version was barely passable.
The Challenge
I don’t like to have my games in a “barely passable” state, so about a month ago, I’ve decided to revisit the code and optimize it.
One thing I’ve noticed right away, was the different “mind-set” the code was originally written. After my past 8 years spent in the game dev industry, the standard was to use various frameworks like PureMVC, RobotLegs, InversifyJS or Zenject, going back to code that doesn’t use any of these feels a little out of place. However, that was not the issue that was keeping That Word Game from performing, so I had to keep back from – actually – rewriting the whole game.
The immediate goals were to optimize the physics simulation and optimize the rendering.
First thing, was to replace the not-so-well aged Physaxe with Box 2D. They are fairly similar, but the newer Box 2D uses fixtures and doesn’t limit the size of the world, so the refactoring went quite deep in this regard. In the end, the game was running, but the performance was still not what I wanted.
The next part of to look at the letter collision shapes themselves. The way I did it back in 2008 was to export each letter from Truspace 3D as a Direct X .x file, then parse the file using a Perl script to create each letter collision shapes (which, all of them, are triangles, to go around the concave limitations Box 2D has).
As I went through the original letter collision files, I’ve noticed that the contain lots of extra vertices and triangles. Originally, I’ve chosed the font to be as square as possible, thus keeping collision shapes to a minimum, but it was still too much for the Javascript port.
Since I don’t have a Truspace version anymore, I’ve decided to go with Blender, which, luckily, has a Direct X .x files import/export plugin, which seemed to parse the original ones exported from Truspace and on I went to clean the shapes.
Additionally, That Word Game would use the very same collision shapes for drawing into a Graphics instance. However, this impact the performance, since, for example, the collision shape for letter A is much more simpler than the one for rendering. As of such, I’ve proceeded to refactor for separate rendering and collision shapes, and, finally, the frame rate went up.
There are still some issues where shapes may penetrate each other which I assume it’s Box 2D cracking up at joints, but, overall, for this particular type of game, it feels OK.
Room For Improvement
Each letter/special shape is drawn, at runtime, into its separate Graphics instance using fills and moveTo/lineTo commands, a Glow filter is applied, then are rastered to bitmaps. Since they don’t use a texture, each letter is a separate drawcall, which results, in well, about 60-100 drawcalls per frame. Not a bit deal for desktop browsers.
The challenge here is that scale for each letter is chosen as a random number in the 1…1.5 range, continuous. As of such, there are 2 ways to improve this.
One is to use only a few scale factors (e.g. 1.0, 1.1, 1.2, etc) and create, at runtime, a large texture that contains each letter and each of its scaled versions. The other is to create a texture just for the renders of 1.0 scale factor, and let the engine scale them, which might result in not so good looking end result.
As would like to take on any of these, as a technical challenge, but, unfortunately, my time is caught creating some new games. Maybe in the future!