Technical Dev Blog #1: Speedier and Speedier
I have to admit that working on our isometric, sprite-based game engine has been an interesting process for me. I’ve been programming for most of my life, but most of my serious programming on video games was done as a hobby 15-odd years ago, and much of my work back then was done using actual, real 2D graphics libraries.
First there was sprites and writing to the video card directly in C in Mode 13H or better. Then, in Windows, there came DirectDraw. Either way, I was still largely working without a modern 3D framework. I’d set the resolution to 640×480 or 800×600 and start writing pixels to what would hopefully be all the right places. Once I had it working, it’d be optimisation time. Just how can I speed up this thing to squeeze every single extra frame out of a given second?
So, doing this again now on modern devices where your sprites are actually just simple polygons sitting orthogonal to the screen at all times is quite a shock to the system, really. These video cards – even the ones on the iPhones we’re developing for – are insanely fast. They’re built to render thousands of polygons at a given time, so drawing a few pesky sprites on the screen is pretty trivial.
On a first test of roughly the size of world we’d need to render with roughly the right number of sprites (up to 3500), even the fairly low-spec’d iPad 1 didn’t slow down too much – and we’d normally never be seeing the map that far zoomed out (Which means we should make the world MOAR BIGGER!!! – Leigh).
So far, so good – but I still felt the urge to optimise. Now, certain sprites in our engine are used over the top of other terrain features to make the transitions between edges look smooth. I wrote a nice little routine to automatically figure out which sprites are needed and put a combination of two in place to look slick. But my brain still said, “Why have them as separate sprites? They only get calculated once. I could just blit the overlays onto the sprite below and be reducing my sprite count by dozens and dozens each screen!”
It seemed like a good idea, but that was only because I was still thinking (sometimes) the wrong way.
Now, a modern sprite engine or piece of middleware like the one we’re using does much of its own texture management. Got seventy instances of the same sprite? Doesn’t matter. It still only loads the texture once.
Fortunately, I spoke to the more savvy coder on our project (I’m generally doing the grunt work, and handing off the more complicated maths or rendering stuff to him), and quickly realised my idea was a really bad one.
If I’d gone ahead and blitted those terrain transition sprites before unloading them, I’d have created dozens and dozens more unique sprites – and eaten up even more of the precious, precious memory space. Maybe that’s not a problem on the 1GB iPad 3rd gen, but on an iPhone 3GS… ouch. There isn’t much wiggle-room on that thing, comparatively.
It’s been great seeing how many of skills coding other sorts of projects transition nicely to game development – heck, my experience with HTML and databases has sometimes clearly given me an edge in some cases. However, it is always important, as I’m re-discovering, to know where the bottlenecks are in your chosen platform, and where its strengths lie.
Many sprites? Not an issue.
Many unique sprites? Welcome to low-memory-ville.
Still, thinking back to what it must have been like squeezing, say, a whole universe into 32kb of ram… wow. We have it easy doing 2D these days.
There’s just no excuse for your game not being lightning fast and pretty any more.
(No pressure on us, then…)