Smashed was the first game I shipped for iOS. It was a physics game, where you had to smash down the architecture on each level to achieve certain goals. There were 8 episodes, with each episode containing 8-10 levels a piece. My brother helped create an awesome soundtrack for the game.
This is just a couple of random thoughts about the development of the game.
I ultimately decided to write my own game engine for Smashed. There were a couple of reasons for this:
It was basically impossible to predict how players would approach the game. I had to plan for the most complex possible physics interaction on each level. But this proved to be a problem; the complexity of the physics interactions caused extremely slow frame rates on basically all the iOS devices. This was true even with all of the gcc compiler optimizations turned on. Back then, the compiler wasn't really tuned to take advantage of the available hardware.
Ultimately I had to dive into ARM assembly, writing matrix calculation functions that could take advantage of the SIMD instructions. This was doubly complicated, because the iPhone 3GS had a completely different floating point chip (NEON on the Cortex A8) to the older devices (VFPU on ARM1176JZF-S). This was all worth it in the end: the game was very playable even on the crappiest iPhone.
For what it's worth, writing assembly by hand allowed me to take advantage of the vector floating point unit on ARM1176JZF-S processor (iPhone 1G, 3G, iPod Touch 1G, 2G), for which you could perform an entire 2D matrix multiplication in one CPU clock cycle. This was similar on the NEON chip on the A8, which was even more powerful.
There was a whole host of runtime optimizations like this, and a whole lot of graphic features were automatically turned off depending on what device the game was running on. There were essentially four categories:
When I shipped the game, there was little support for OpenGLES 2, and thus I was stuck without the use of shaders. The fixed function pipeline is truly pretty awful, but I made it work with some fairly questionable hacks. One in particular re-used the previously mentioned matrix operations to do real time, per-vertex, lighting. This was a questionable decision, but I had CPU cycles to burn, and I just couldn't get the look I wanted with fixed function lighting extensions.
The game ultimately shipped with about 70-80 levels. It was extremely creatively difficult to create all of these levels and I felt physically drained afterwards. Each level had to be different than the last, building on skills taught to the player in previous levels. At the same time, you had to introduce new features to the player to keep them invested in the game.
For each level, I would sketch out a design concept on paper, and then imagine how it would play. This step at least filtered out the truly terrible ideas. If I thought a concept was worth pursuing, I would load up my custom level editor and build out the basic concept, and then test on an actual device. The trouble was that each concept has a "fun threshold" that you need to reach before you can definitively say that it is worth keeping or not. It might take some time refining before you reach this threshold. Many designs proved never to work when I tested them on an actual iOS device and I had to make the judgement about whether to continue improving them. I estimate that I tested 500 concepts, to get the final list of 70ish that the game shipped with.
Oh, and, once the level was complete from a gameplay point of view, I had to texture it, add backgrounds, and fit it into the story.
I was very proud of the work but creatively "spent" afterwards.
When I shipped the game it exceeded the 20MB download threshold by a fair margin. Just the sound and music files alone almost exceeded that limit. But I still wanted to keep the app size down below 50MB, which proved to be difficult with a graphics-heavy game.
Simply compressing everything was a no-go, because of an added limitation of the runtime memory limits of the iPhone 1G and 3G. I think we had a paltry amount of memory to play with, and a "burst" of even loading even 20MB into memory would simply cause the OS the terminate the app. This meant that you couldn't reliable decompress big file blobs at run time. The bandwidth available to load a file from disk was very limited and slow, relative to what we are used to today. Loading a big data file into memory, pick what you wanted from it, and then freeing the memory was simply not an option.
What I ended up having to do was to create a custom file format. The format was a single "master" file with a binary manifest at the head, followed by concatenated zipped data blobs, each blob holding a texture, font, sound effect, etc. The manifest contained the ID, location and length of each file in the master. To load a specific blob, the manifest was directly read into memory, and then the master file was memory mapped.
To ensure that only the required files were loaded, each level had its own data manifest. Only the required files were read from the master, then decompressed, and then loaded into texture/sound/computer memory. This all happened in series, but it was very fast and game levels loaded very quickly on the crappy iPhone 1G.
I made a couple of other optimizations worth noting: