Physics Game for iOS

Objective C

Smashed (2009)

Physics Game for iOS

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.

Custom Engine

I ultimately decided to write my own game engine for Smashed. There were a couple of reasons for this:

  • I wanted to learn how to do it, and thought I had the skills to do it.
  • There were no decent game engines or dev tools for iOS at the time. I don't even think Unity supported iOS until 2010, and it wasn't really worth using for iOS until 2013.
  • I would have complete control over tooling, optimizations, and so forth.

Optimizations for iPhone Floating Point Chips

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.

Device Optimizations

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:

  1. The lowest graphics setting (30fps, limited particle effects, lower physics simulation cycles, 256 color textures, no lighting): iPhone 1G, 3G, iPod Touch 1G
  2. Overclocked device setting, which had lighting turned on and slightly better physics simulation: iPod Touch 2G
  3. High graphics (full particle effects, reflections, physics, lighting) with low res textures: iPhone 3GS and iPod Touch 3G
  4. All graphics settings on max: iPad (released 9 months after Smashed), iPhone 4

Fixed Function OpenGL

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.

Level Design Process

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.

Memory vs Speed Trade Offs

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:

  • Only high resolution textures were shipped with the game, but these were downscaled at runtime for lower quality devices.
  • All data files were converted to binary, meaning they could be directly loaded into memory at run time. This was particularly important for the level meshes, which could contain a lot of data.
  • The level meshes were all stored in 2D: the 3D data was all generated at run time.