It’s been eleven days since I last updated this blog and two weeks since I wrote about something I’d actually done to progress my game. Last time I wrote about my project I had just finished writing the level loader using pugixml and was refactoring my prototype code into something more generally useful and game-loop like. With each generalisation I added I was removing some presumption I had previously been making, where each of those presumptions had allowed me to not have to think about tricky edge cases or how some feature would work in a fully-fledged game.
In the prototype, if I added a physics object here and a physics object there I could vaguely test the physics system and see if it worked and gave the kind of feel I was looking for. If I placed the two physics objects on top of each other and they interacted badly, I could fix that by just keeping them apart for now and worrying about the issue later. When moving towards a more robust system that I can use to test out a multitude of game ideas, dealing with edge cases, rather than working around them by not using the system fully, stops being an option.
For instance, when I started writing an asset manager to deal with loading textures, I remembered Adam Clixby’s advice about testing in low-memory environments and factored that into the design. So any reference to assets in the game is managed by handles passed to the asset manager and would be agnostic of the state of that asset in memory. A game object might use a specific texture and on creating that object I tell the asset system to give me a handle to that texture, so that later I can bind the texture before rendering the object on screen. In this context that handle is an internal type of the asset system and on passing that handle to the asset manager to get hold of the texture name to bind it, the asset manager will then load, reload or pass an already loaded texture name back for rendering. Now, if I get a message from iOS that the device is getting low on memory, I can dump all the textures and know the system will smoothly reload them when my game becomes the currently interactive app again.
The asset system also deals with multiple objects using the same texture by simply returning the ready loaded texture handle when an identical texture is required from another source (identical by filename currently, hopefully this won’t cause too many issues later). This doesn’t cover all my needs though, as I have textures I adjust during gameplay and could be updating them every frame. There’s an overhead to constantly loading textures into graphics memory, but it’s a requirement for what I’m doing and isn’t prohibitively costly. What it does mean is that I might start off with a 128 * 128 texture, where the texels are being changed frame by frame, then later resize the texture and load new images onto empty parts of the resized texture. Keeping the game in lock-step with these changes, such as resizing arrays in the game for data that relates to the textures and copying old and new data into the correct portions, has taken a good proportion of the last two weeks to get running robustly and without the heart sinking feeling of suddenly seeing uv coordinates flying all over the place as some part of the system gets out of sync with the rest of it.
The result is that I now have a game that can load levels from xml, create game entities and run the gameplay, so that I can quickly prototype a variety of game ideas around a theme. It’s definitely taken me longer to get things up and running this way and I could have been prototyping game ideas in a more throw-away manner, but everything I’ve taken time to code in a considered way are systems that I will need for making the final game and any future proofing lies within the scope of the current project and on the initial platform. It feels like I’m half in full production and half in prototyping but if I’ve balanced it right then the bits in full production are the bits I know I’ll need in the final game and the bits I’m prototyping in a quick and dirty fashion are the bits that will be used to reduce risk and can be happily thrown away. The ideas that make it can then be moved into production territory, once the prototypes have led to definitive design decisions and it’s not a waste to spend time doing it right.