Sun, 6 Feb 2011
By Thomas ten Cate
Game development can be a pain sometimes. Remember my writings on threading last week? This week has been more of the same kind of stuff: engine improvements, code cleanups, bugfixes, and only some small new features that are actually visible.
Did I say visible? I meant “audible”. The biggest change on the surface is that some nice music now plays during the game. It even pauses and resumes correctly, and all this took just one hour to set up. Android does have its merits sometimes.
It’s still just one tune that I stole from somewhere, which I’m leaving in to see whether it becomes annoying. Because writing music is not exactly my specialty, I’ve been looking around on the web for songs that I can legally use, either for free or for a small one-time fee. For the final game, I want at least one song for each supermarket ‘chain’, and a separate song for the menus. Depending on cost, file size and availability of suitable songs, I might add some more for various menu screens, the game-over screen (depending on whether you won or lost), and the end credits.
Other improvements… well, bits and pieces. Let’s have a look at the commit history. Sorry that this is all technical stuff again, but it’ll allow me to start adding more interesting new features more easily next week.
First off, I refactored the renderer. Previously, each render phase had its own
tearDown methods, which initialized and reset particular OpenGL settings used during that phase. Since there were about 10 different phases, it became difficult to keep track of what state changes were actually necessary. In the end, I put them all into one big method. From that, it was easy to see that many of the changes were actually undoing a setting from the line right before. Eliminating these redundant state changes gave an immediate speed boost of over 5%!
Making better use of texture atlases, I could also eliminate many
glBindTexture calls. The texture used by any object now does not depend on the object at all, but only on the render phase it is rendered in. There are only four textures in the entire game, and I could reduce this to three or maybe even two (one for level-dependent stuff and one for global, level-independent stuff).
Then I added a new utility class called
FastArray. Like the standard Java
ArrayList, it’s a dynamically resizing wrapper around a plain array. The difference is that the underlying array is
public, which allows us to avoid
array.get(i) calls and simply write
array.elements[i] instead. In tight loops, this makes a big difference. In extreme cases, we can even assign
array.elements to a variable to avoid a lookup.
I also moved most assets (textures, models) from the
assets/ directory to the
res/raw directory. In the Android build system,
assets is something you have to manage manually, but
res/raw is managed by the build system. The result is that, instead of using filenames for textures, I can now access them through an integer identifier, like
R.raw.myTexture. If I rename or remove a file, instead of the game crashing at runtime, the build system will now rebuild the
R class and the code won’t compile until I’ve updated all references.
My neat custom texture format, which could be zapped off to OpenGL byte-by-byte, turned out to be too big for distribution. I replaced all textures by PNG files instead at the cost of some more loading time.
And because the loading time became longer, I have finally added a “loading” screen. It’s just the title screen with the text “Loading …” superimposed, but it animates out nicely when loading is complete. Getting this to work was tricky, because the game thread has to load the level first, then the OpenGL thread has to load the assets, and finally the UI thread has to hide the loading indicator.
One other change that I’m quite happy about is support for sprites. Previously, a “sprite” was simply a full-blown 3D model that happened to consist of a single square or rectangle. For each new sprite, I had to launch Blender, draw the square, map the texture, and rebuild. Now sprites are created on the fly by a dedicated class, so I can add new ones much more easily (although I have to look up and hard-code the texture coordinates by hand). I modified all objects using sprite-like models to use these sprites instead, which are a bit more efficient, because they can cheaply be translated and rotated on the CPU side and then all rendered in one big batch. (This isn’t actually happening yet – future work!)
And finally, as usual, there were numerous problems that I introduced while making all these changes… but I think I got them all fixed up now. Next week, it’s time to build out again!