The following is a continuation in a series of articles on porting apps from the iPhone* to the Intel AppUp® center. This is my interview with developer James Brown on his experience in porting his award-winning game "Ancient Frog" from iPhone* to the Intel AppUp Center.
Ancient Frog was born out of my departure from the mainstream games industry. My background was very broad—designer, programmer, artist, producer. But the games industry had become huge and stratified, and I ended up at Lionhead / Microsoft as a manager of a team of programmers with no real creative input, which was about as far from my ideal job as I could imagine.
I decided to start my own games again. I was led to the idea for Ancient Frog by the constraints I had set myself. I needed a game small enough that it could be completed to a professional standard by a solo developer. With a puzzle game, once you've nailed the puzzle mechanics, the rest is just variations on that theme. I also wanted a central character, cute without being cutesy, with a bit of personality to it. Since I'm not an animator, that set me looking into procedural animation systems, and the idea of a rock-climbing game involving a gecko sort of coalesced out of that.
Once I'd thrown together a stick-figure prototype, the idea morphed and evolved as I played around with it. The gecko became a frog because frogs have longer legs at the back than the front, which introduces some interesting decisions for the player. The climbing aspect faded out to the slightly more abstract stepping-on-droplets idea. The animation system became more explicit—you don't drive the frog, you drag one limb at a time—which both made it a more interesting puzzle, and meant that the player was the one creating the animation, rather than the game.
It was quite a prolonged journey from that initial prototype to the final game (during which time I changed country and spent a while building digital interactives for museums), but the fundamental idea remained very clear in my mind throughout.
The main tool used in the creation of the game was the game itself. The majority of the code written for Ancient Frog went into the internal tools and editors (including code for generating the puzzles, and for finding the optimum solutions to them, which was a particularly interesting challenge). By far the most important aspect in pinning down the design was the fact that everything I could I made modifiable on the fly. There's no substitute, when it comes to building an enjoyable interactive experience, to constant iteration. Try something, test it, fix it, test it, round and round until all of the snags and irritations have been removed. Then keep going to add the stuff that delights and surprises. Then round again to remove the snags and irritations that introduced.
Everything is driven by the data, and by monitoring the disk for changes the game can seamlessly reload any edits. Paint on a texture in Photoshop*, hit save, and there it is in the game. There are no magic numbers in the code—I have a little templated 'rule' class which behaves like a native type, so there's an extremely low threshold of convenience for exposing everything to the data. The springiness of that leg? The duration of that crossfade? The acceleration due to gravity? Even if I'm sure I'll never want to change it, it's there, and if the whim takes me while I'm testing, I can just fiddle with whatever I like and see what happens as I do it. If you need to stop, recompile, and play back to where you were, you quickly reach the point where a change is too much trouble to bother with.
The particular look of Ancient Frog really grew out of a self-imposed requirement for maximum resolution independence. I wanted to run at anything from 640x480 to, say, dual-monitor 1920x1200, and any aspect ratio from portrait to wide-screen. One of the things that had annoyed me about my previous game at Lionhead was that changing resolution required restarting the game. Now I was doing it all myself, I wanted to do it properly, so not only was I going to allow resolution changing on the fly, I was going to make it so you could grab the window and drag it to any shape or size and watch the content seamlessly adjust itself as you did so. It seems like a strangely trivial technical decision, but it ended up having a huge impact both in terms of the unique look of the game, and in the ability to port to widely varying platforms.
If I'd just settled on a handful of sensible aspect ratios, I could have got away with authoring the graphics with a bit spare around the edges and cropping to fit, but the fact that every time I ran the game I could fiddle around with the window size meant that I wanted to see what would happen if I made it really wide. Or tall. Or huge. Or tiny. And when you do that, you quickly run into the limits of fixed layouts. So I built a layout engine driven by xml level files, which built up levels in layers. Each layer can have all sorts of layout rules, but the basic strategy is to have a layer to hold the play area which tries to be as big as will fit in the window, and one or more layers of foreground and background which can be tiled, stretched or cropped to fill the rest of the screen.
Once the idea of building the levels in layers had appeared, it was natural to use that to introduce some life and motion to the screen, some depth of field, some parallax. I used photographs to supply the textures for the layers—leaves, tree trunks, moss, stones and so on, and there was something promising about the approach, but for several months it wouldn't come together as a coherent whole. The breakthrough came when I was clearing out the gutter in front of the house, and became distracted by the pattern of shadows from trees on the garage door. It was a constantly evolving dance, but with an underlying simplicity based on the interaction of a few simple shapes and rhythms. When I went back inside, I coded up a copy of that effect and layered it over each level using multiplicative blending to give everything a rich saturated look, and that ended up cementing the style of the whole game.
Ancient Frog is available on the Apple* iPhone* and iPad*, Palm* Pre* and Pixi*, and now Intel® Atom™ processor-based netbooks. I also have an Android* port (but currently no way of selling it from New Zealand), and desktop PC and Mac* versions where I'm still dithering over the best sales channels.
The initial prototype was actually written for my phone (at the time, a Windows* Mobile device with a 240x240 screen). Most of my game playing was happening in odd moments at the bus stop or supermarket checkout, and I wanted to create something in that vein. But this was before the iPhone* came along—the smartphone space was very fragmented, and I didn't really have a clear idea of what spec I should be targeting or how I'd be able to sell a game to smartphone users. So I set that aside, and shifted development to the PC. But the idea of putting the game on the phone at some later point stayed with me, and throughout development, portability and scalability were central to my thinking.
I've found that the less I'm dependent on external libraries, the more portable my code is. There are certainly good arguments for all manner of utility libraries, engines or middleware, but they're only an advantage if they get to an interesting target platform ahead of you. If it turns out one of your dependencies doesn't work on the target you're interested in, then there's not much you can do about it. I do use SDL (the Simple DirectMedia Layer) on the PC, but it's a very slim layer and easy enough to code up alternatives if you need to (as I had to for iPhone* and Android*).
Otherwise it's just C++ code targeting OpenGL*. C++ is a safe bet—whatever weird language may be recommended on a particular platform, you can be pretty sure the C/C++ compiler was there first (if only to compile that language). OpenGL* is very widely available by default (even on Windows*, they'd rather you were using Direct3D* but aren't going to go quite as far as insisting on it). It's also very easy to use a well-defined subset of OpenGL*, and on platforms where it isn't available, implement just that subset yourself.
I do the majority of my development on Windows* using Microsoft Visual Studio*, but I use a MacBook* Pro for development if I want to get out of the office. It's very healthy for the portability of your code if you're regularly building under two different compilers and operating systems. That's enough to flush out the majority of any cross-platform issues before they settle down and get dug in somewhere awkward, so I haven't had many surprises when porting to another platform.
The game already ran on Windows*, and netbook resolutions were covered by the work I'd done there originally, so 'port' is possibly too grand a word for the work that was required.
I wasn't able to test on a very wide range of target hardware, so I built using the most conservative settings—my game engine has a few settings I can use depending on the capabilities of the target, and I turned off framebuffer objects and shader support. When I have a bit more data on the level of driver support out there, I'll probably turn them back on and make the game a bit sparklier.
Ancient Frog doesn't really use any hardware that can't be replicated with a mouse or trackpad. I do use the accelerometer to influence the direction the petals fall in the 'win' animation, but it's hardly a game-breaker to lose that. Multitouch is used on the iPad* version so that you can dip more than one finger in the water at once—again, no big deal to lose out on that.
On the touch-screen versions of Ancient Frog, the game starts with an introductory tutorial which takes control away from the player. This is admittedly annoying to some players (but play-testing had shown it was necessary to teach some of the control gestures). But for some reason, on a machine with indirect control—a mouse or trackpad—it becomes completely unacceptable. I'm not sure why—possibly it's that not responding to a touch is something that's always context-sensitive, and so expected, while not responding to the mouse feels more like the machine has hung, and is not expected.
At any rate, I had to change the tutorial to be a more hands-off piece of advice. I also removed the gestural 'undo' and 'redo', partly because gestures are awkward on a mouse/trackpad device, and partly because the increased screen space means there's room for on-screen buttons. Having buttons on the screen also means the player is encouraged to play with them to see what happens, which removes some of the load from the tutorial.
The approach Ancient Frog uses to create its look, with multiple blending passes, is very fill-rate intensive. I'd had a hard time of it on the iPad* port, which I'd done just before the netbook version, because the iPad*'s GPU simply can't handle that much overdraw. I had to put a lot of work into baking the lighting in to the textures, removing elements from the layout, and generally slashing it down so that it would run. So I was worried, coming to the netbook version, that I'd have the same problem. As it turned out I was pleasantly suprised by speed of the integrated graphics chip, and I didn't need to cut anything.
The game play is essentially the same on all devices. On the handhelds, the look of the levels is simplified—they just have one layer, and are cropped tightly in to make the most use of those tiny screens. On the netbook versions there's more room for the frogs to breathe, and some playful background elements to prod at. But apart from some small tweaks to the difficulty progression, the puzzles are identical.
The whole process was straightforward. I had one validation failure because I'd managed to build against an old version of the SDK, but after that everything just sailed through.
The only thing I'd do differently would have been to do it sooner. There's so little effort involved in building for the Intel AppUp center, and I'm really excited to see where it goes.
The best advice you can have for porting from iPhone* to the Intel AppUp center is to build your iPhone* app with porting in mind from the beginning—use straight C++, and avoid the Apple*-specific APIs. If you've already finished your iPhone* version and you're wondering whether it's worth the work refactoring it to be more platform-independent, there are benefits for the original code quite apart from having a new port. Different devices tend to expose different subtle bugs, and since the code is the same across all platforms, the fixes you make will benefit every version.
If you're going to build for both iPhone* and the Intel AppUp center, it makes sense to treat the Intel AppUp center as your primary target during development. You want to be able to iterate quickly, and debugging to a netbook is considerably faster than the iPhone* simulator or downloading to the physical hardware.