It’s been busy, busy, busy as of late. We’re in full swing trying to get Tilt to Live HD ready for the iPad. It’s looking amazing thus far and plays a lot better than just the 2x mode for the original Tilt to Live. Frostbite mode just went out the door a few days ago, and the response has been positive so far. We’ve been getting some responses from users saying the game has become too easy in the other modes. I haven’t tweaked anything in the other modes for ages so my hunches to why users are believing this are:

  • It’s been a while since they’ve played and when they came back it was like riding a bicycle and they instantly got into the flow of the game.
  • Performance has degraded on the lower end devices (particularly when running iOS4), which slows the game down and as a result makes it ‘easier’.

I’ve tested the game on a 2nd gen ipod touch with iOS4 and it seems to run fine performance-wise. So it’s something I guess I’ll just keep on my mind when doing further updates to the game. Maybe revisiting Code Red mode and making it even harder could be a possibility to appease the hardcore users.

Some Reading Links

Whenever I have time to kill I go browsing through my RSS feed to catch up on things. I decided to share a few of my usual reading links. Maybe you’ll find something of interest in this pile as I tried to focus on reading links that are outside the iphone development community. A lot I’m sure are common go-to places for a lot of indie devs regardless of platform.

Cliffski’s Blog

I feel like just about anyone that has any semblance of what goes on in the indie world is at least aware of Cliff Harris and his musings on his blog on both his own games and the industry as a whole.

Fullbright

Steve Gaynor’s [Bioshock 2] video game design blog. Always a good read and has valuable insights into not only the design of mechanics in games but about the medium of games overall.

Shawn Hargreaves

For a time I worked mostly in XNA and C#. While most of his recent posts are about gearing up for windows phone 7 and other XNA tech, his technical but easily readable posts were extremely helpful not just in XNA, but any platform you may be starting out on. Great learning for those that don’t have true game industry experience (like me). His credits include Extreme-G (N64), Moto GP (Xbox/PC), and several other racing games.

Mark Sibly

Ok, not many updates for this blog but that’s not the point. Creator of Blitz Basic and Blitzmax. For those that don’t know anything about it, Blitzmax is a very nice cross platform language (PC/Mac/Linux) for developing 2D (and 3D) games. It’s a very small and friendly community, but one I spent a lot of time in when I first started getting serious about making independent games. The tech he currently is working on seems like really exciting stuff: A language that allows you to target HTML5, flash, XNA, Android, iPhone, native GL for game development. Very ambitious, but very exciting to keep tabs on!

Beautiful Pixels

Great graphics and game development blog. I believe he recently went to work for Google on Chrome OS. Great posts to browser through, and I’m sure some very useful ones in the coming future. Despite having a lot of ‘game oriented’ blogs on my feed, I tend to follow developers outside the game industry as well. And now that he’s at Google, I’m sure lots of good will come of it :).

Game Architect

A great blog on finding the ‘hard to find in a book’ answers to questions that come up during development. Like what’s a good way to keep you from creating a crazy object hierarchy but still have flexibility. Great thoughts on middleware as well.

Grey Alien Games

I’ve been following Jake Birkett for several years now as I was going through high school and college. His success as an indie was very inspiring. Great place to read for motivational and lifestyle posts as well as general independent game development. He was also a very involved community member in the Blitzmax community, writing a pretty successful game framework to allow developers to more quickly make indie casual games on the PC.

Lost Garden

If you haven’t heard of this site and Danc by now, then…I don’t know what more to say.

Pandemonium

Andy Patrick’s blog. Great info from an experienced developer. He previously worked at Rare on Kameo and Viva Pinata. Hasn’t had an update in over a year but some good content on programming things like cameras, game programming in a garbage collected environment, and tool recommendations. One article I really liked was going over how to implement infinite undo/redo in an game editor.

Sell More Games

Great site has articles focusing more on the marketing and business side of indie game development. Mostly geared towards the PC market, but I feel all of it is still applicable to the iPhone market.

Make it BIG in games

I believe I’ve referenced Jeff Tunnell’s blog entries before, but it’s worth listing again.

Gausswerks Design Reboot

Another great game design blog. Less on the technical and more on the design and art of games. I’m ashamed to admit I don’t read enough of these articles.

Ahh, my first idevblogaday post! For those that don’t know, idevblogaday is a group of indie dev bloggers started by Miguel Á. Friginal of @mysterycoconut games to get developers blogging more regularly. So we’ll see how that goes :]. After finishing the initial release of Tilt to Live I had been wanting to gather up my thoughts on what I had learned about making a game that is heavily dependent on accelerometer controls. Sadly, this was on the back burner for the longest time. I eventually got contacted by Noel Llopis of Snappytouch and through some e-mail conversations with him I was able to get some of my ideas finally in writing. So now, I figured I’d take that and present it to everyone to see, learn, and laugh at my horribly awesome code.

Some Background

I want to give a quick and dirty history of Tilt to Live (TtL). This is not a post-mortem quality account (That will come later), but something so readers have a context of how TtL evolved and where it came from code-wise. TtL was the first app I wrote for an iDevice platform, ever. First time using a mac regularly, first time using XCode, first time using Objective-C. There were a lot of firsts. Typically when I’m learning something I don’t bother with style or best practices, or platform specific conventions. I learn all that as I go. TtL has come a very long way from the first iteration of it.

Then

The first signs of things to come! The green dots are what are considered the ‘nukes’ in today’s TtL.

..and now:

 

While the game is pretty, thanks to Adam’s Awesome Art (AAA quality!!!), the code at times can feel like one giant ugly beast. Usually  when I’m in an environment I know well, I write a prototype, then start over and write the game ‘correctly’ so the code can be maintainable throughout. Not so with TtL, this game evolved straight from prototype hack-a-thon to full on production code. The code base went through lots of rewrites, refactoring, and dubious ‘fixes’ to keep things somewhat on the side of sane. On the bright side, I now have a much clearer idea of what ‘maintainable’ code shouldn’t look like and a lot of design decisions I know to make earlier on in the coding process to avoid some clunkiness in the future. There’s certainly something to be said though for making it ‘just work’ because in the end, no one gives a damn (except the author) how it’s written as long as the game is fun :].

With that said, I’d like to talk about some of the design issues we came across while developing TtL’s tilt controls.

Design issues with tilt controls

Our main area of focus on ‘controls design’ was how to present calibration to the user. Overall, we had a very minimalistic approach to the game’s user experience. We wanted minimal taps to get into the game, and once in the game, all you did was tilt to interact. Naturally, having calibration be automated seems like the ultimate in minimalist user-experience. The user doesn’t even experience it. It’s supposed to “just work”. So how did our calibration work initially? Well, when the game counts down on ‘3,2,1’ and the ‘1’ disappears the game calibrates at that point in time as the neutral position. Also, when the player unpaused the game, it would recalibrate. Sounded great, and it worked great…if you understood how it worked. From playtesting we found:

  • Users would get confused as soon as they change their play position (from say, in lap to on top of a table) without pausing the game. It was a cause of frustration for them.
  • The more savvy players immediately looked for options to calibrate because the terminology was engrained in them from previous iPhone games. Without options to calibrate they felt frustrated that they could not control the way they’d like to play.
  • In more social settings rather than isolated playtesting, the game would be played haphazardly. This caused all sorts of havoc on our auto-calibration scheme. The player would either lay the phone down, swing it down to their side as they’re talking to their friend while the count down is going on and then when they’d swing it back up again to play the calibration is royally screwed up. This didn’t make for a good first impression either. Ouch.

So what happens when we decided to tell users that pausing and unpausing the game would recalibrate the game before they played? We did that as a quick way to emulate ‘custom calibration’.

  • For the group of users who understood the technical need of calibration instantly got it.
  • Everyone else pretty much said “What ees des calibration meen?”. Yes, in bad fake accent and all.

Well, since we wanted to appeal to more than “hardcore” (I use that word very loosely here) iPhone gamers we had some take aways from the testing:

  1. On auto calibration: Without proper feedback, the user can set the calibration very wrong, making them think the game is broken.
  2. On custom calibration: Some users get it, but with a near infinite number of choices to the user, it’s hard to expect a non-gamer to know what the best setup/calibration would be.
  3. On choices in general: Experienced users like it, nay, demand more options. The fewer decisions a user has to make on how to “play” your game, generally the more accessible it is. A powerful concept in the mobile space, especially with non-precise/noisy physical inputs like accelerometers.
  4. In respect to TtL’s design specifically: TtL’s gameplay requires accurate tilting controls or the game falls flat. Other games that require less precision can certainly get away with auto calibration.

So after brainstorming a few ways to present a new calibration screen, Adam had a pretty unique idea compared to most tilt-based games at the time:

While we thought it was a good idea and it playtested well, we didn’t think the preset choices would resonate with users as much as it did.

“The game has some of the best options I have found for customizing the tilt controls.” -Nate Adcock, iphonelife.com

“For those of you worrying about manual calibration, don’t.” -nodpad.com

“Unique to this game is a calibration option that provides three default control schemes that should satisfy most positions that you’d like to hold your device in.” -Ben Briggs, gamesuncovered.com

 

Players and reviewers alike seemed to respond positively to our approach of essentially what is just a common preset list. The regular setting works for the vast majority of play cases and top-down works great for the purists. Sleepy was a rather experimental one that has mixed results. It works for me, but if you ask a group of players to play in a “sleepy” position you’ll most likely get a higher variance of orientations than what “regular” and “top-down” imply. I don’t think our technical implementation of tilt controls was any more accurate than the next game’s, but I feel because the user was able to more accurately set the game up successfully with a reduced number of choices their experience was much more positive.

Technical issues with tilt controls

Design issues aside, the technical side of my approach to tilt controls had a few issues I had to overcome as well. The first and biggest issue was a limitation of how I went about calculating the tilt offset. As the calibration of the iPhone approached a purely vertical orientation, detecting horizontal motion reduced to zero pretty much. To counteract this, I added an additional control scheme for when the device was in such a position and require the player to move the ship by “steering” the iPhone instead of tilting. Not the most ideal situation, and with the advent of the iPhone 4’s gyroscope this could probably be mitigated. There are certainly ways to implement tilt controls on the 3G/3GS where this isn’t an issue, but I haven’t had much time to experiment with them yet. I’ll certainly post an update on my findings as I get to them.

The 2nd issue was noisy accelerometer data. I had experimented with filtering the raw input, as per Apple doc recommendation, but in the end I let the input through unfiltered and just altered the rendering of the ship. Rendering the ship’s orientation based on the raw data caused the ship to shake uncontrollably as if it was hyped up on speed. Also this would make it impossible to use any weapons that required aiming. Solving it was pretty basic as I just added an interpolation function that would ease the ship to the current desired orientation over a couple of frames and adding a dead zone so that players can sit still without spinning wildly. I’ve played a few tilt-based games where the players’ avatar had an orientation and no dead zone was implemented. Be nice to your players, add a dead zone at the very least damnit.

A 3rd but minor issue was with sampling rates. I sample the accelerometer at 30hz and TtL runs at 30FPS. When (not if) the FPS start dipping the accelerometer data seems to get a bit out of sync and you start seeing small jolts of movements from the accelerometer data that came in between some of the frames. TtL doesn’t do much in managing varying frame times (shame on me), but this problem hasn’t brought much pain so I’m not looking at it worth fixing yet.

Well how does it REALLY work?

For those that are still reading this and are curious to see how it’s implemented I’ve attached a sample XCode project with the implementation that TtL uses. I took a GLSprite sample project and mutilated it until it resembled a sufficient “tilt controls sample”. The approach I had in mind was to make the iphone function as a “reverse” joystick. I’m not even going to try to explain WTF that means in text so here’s a poorly drawn illustration:

I  interpreted the accelerometer data in a way that would project a vector that always pointed away from the screen of the device. I would use this to find the difference vector between it and the ‘neutral’ position (blue) and finally project this onto the 2D plane of the screen to give me a velocity. The green arrow is what the player’s velocity was set to. So when the neutral position and inverted accel data are very close to each other, the player’s velocity is clamped to zero (deadzone).

 

You’ll find in the sample project that all the relevant accelerometer logic is implemented inside the TiltPlayer class in the ‘accelerometer:didAccelerate” method. Inside the TiltPlayer’s ‘update’ method it handles the smoothing of the icon’s rotation to reduce jitter. The rest are just supporting classes for rendering and other boilerplate code. So for those that wish to just see the pertinent code without firing up XCode, here it is:

[code]- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
/* while not ideal, most of the relevant code is stuffed in this method for clarity. A lot can be computed once
and saved in instance variables, preferences, etc instead of re-calculating each frame
*/

// hard coding our ‘neutral’ orientation. By default this is the orientation of
// having the device tilted slightly towards your face.
// if you wanted strictly a ‘top down’ orientation then a (0,0,-1) vector would be put here.
// to create a new ‘neutral’ position you can sample the UIAcceleration parameter for a single
// frame and set that to be the new nx,ny,nz for the remainder of the app (aka calibrating).
const float nx = -0.63f;
const float ny = 0;
const float nz = -0.92f;

// this quaternion represents an orientation (I like to think of it as a 3D vector with 0 rotation in this case)
// that points straight out from the device’s back away from the user’s face.
Quaternion neutral(0,nx, ny, nz);
// take a straight up vector and rotate it by our ‘neutral’ orientation
// to give us a vector that points straight out from the device’s screen (at the user’s face)
Quaternion neutralPosition = neutral * Quaternion(0,0,0,1);

/* now with our ‘neutral’ quaternion setup we:
1. take the incoming accelerometer data
2. convert it to a 2D velocity projected onto the plane of the device’s screen
3. and rotate it by 90 degrees (since we are landscape oriented) and feed it to our player’s
velocity directly.
*/

// convert our accel data to a Quaternion
Quaternion accelQuat(0, acceleration.x, acceleration.y, acceleration.z);

// now rotate our accel data BY the neutral orientation. effectively transforming it
// into our local space.
Vec3 accelVector = (accelQuat * neutralPosition).v; // we only want the 3D vector at this point

// now with our accel vector we wish to transform it into our standard (1,1,1) coordinate space
Vec3 planeXAxis(1,0,0);
Vec3 planeYAxis(0,1,0);
Vec3 normal(0,0,1); // the normal of the plane we wish to transform our data into.

//project this movement onto our X/Y plane by removing
// the accel part that is along our normal
// note: Vec3 * Vec3 = dot product of the 2 vectors.
Vec3 projection = accelVector – normal *(accelVector * normal);

// now decompose that projection along our X and Y axis that represents our 2D plane
Vec2 accel2D(0,0);
accel2D.x = planeXAxis * projection;
accel2D.y = planeYAxis * projection;

const float xSensitivity = 2.8f;
const float ySensitivity = 2.8f; // yay magic numbers!
const float tiltAmplifier = 8; // w0ot more magic numbers

// now apply it to our player’s velocity data.
// we also rotate the 2D vector by 90 degrees by switching the components and negating one
// since we are in a landscape orientation.
vx += (-accel2D.y) * tiltAmplifier * xSensitivity;
vy -= accel2D.x * tiltAmplifier * ySensitivity; // we do a (-) here because the accel y axis is inverted.
}
[/code]

if you want to download the XCode project, you can grab it here. [note: updated with Mikko’s more concise version below]

That’s it for now. As always, feedback is welcome and if anyone takes that code and improves it, it’d be nice to know :].

*Update*

Thanks to Mikko Mononen for making the code much more concise! Below is the altered method with Mikko’s contribution:
[code]
– (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
// A much more concise version courtesy of Mikko Mononen http://digestingduck.blogspot.com/
Vec2 accel2D(0,0);
Vec3 ax(1, 0, 0);
Vec3 ay(-.63f, 0,-.92f);
Vec3 az(Vec3::Cross(ay,ax).normalize());
ax = Vec3::Cross(az,ay).normalize();

accel2D.x = -Vec3::Dot(Vec3(acceleration.x, acceleration.y, acceleration.z), ax);
accel2D.y = -Vec3::Dot(Vec3(acceleration.x, acceleration.y, acceleration.z), az);

const float xSensitivity = 2.8f;
const float ySensitivity = 2.8f; // yay magic numbers!
const float tiltAmplifier = 8; // w0ot more magic numbers

// since we are in a landscape orientation.
// now apply it to our player’s velocity data.
// we also rotate the 2D vector by 90 degrees by switching the components and negating one
vx += -(accel2D.y) * tiltAmplifier * xSensitivity;
vy += accel2D.x * tiltAmplifier * ySensitivity;

}
[/code]

So I’m using OpenAL to do the audio in Tilt to Live. Over the course of development audio became the bottleneck of my game, both in size and in performance. The following could help you if you’re experience audio performance issues and are somewhat new to OpenAL. Let me preface this with: Don’t blindly optimize. Measure, Measure, MEASURE! Know what your bottleneck is before trying to tune code!

  1. Don’t make more than 32 sources objects in OpenAL. Of course, this number may vary from device to device and what generation the device is. Making any more than the limit the device support makes openAL fail silently, and at this point you’re wasting cycles.
  2. Load your audio buffers and create your source objects ahead of time and re-use them. This is a big one. Don’t generate and delete source objects in the middle of your game update. Instead, it’s much faster to just grab a ‘free’ source that is not playing a sound any longer and attach it to another buffer. I was pre-loading my audio-buffers, but creating/deleting sources on the fly in Tilt to Live. Then I started ‘pooling” and I got a decent gain out of re-using source objects.
  3. Keep OpenAL calls to a minimum. Especially in tight update loops, don’t repeatedly call openAL functions that don’t change frame-to-frame. I found that a good portion of my time was spent doing something as simple as ‘alSourcei()’ on each source ID per frame was causing a significant slow down.
  4. Don’t query openAL state if you don’t have to. In my case, I wrapped openAL Sources in objects with properties to get volume,pitch, etc. Initially those properties simply called the openAL equivalent and returning it instantly. This was hurting my frames due to some some innocent looking “backgroundMusic.volume += someVal” happening each frame along with other audio sources doing the same thing. Save any state you can in instance variables, and as a last resort hit openAL when you need to.
  5. As for size, you should consider compressing your sound FX and music to a reasonable size. If you’re like me, you hate giving up quality; especially if you listen to the full quality one and then the compressed one. It can seem like night and day. But in reality, when your users won’t have a full quality audio file to compare it to, they will not notice the difference.

As a sidenote, you can look at my first dev tip for batch compressing audio files.

We’re extremely close to submitting our first title “Tilt to Live“. We plan on submitting it this upcoming Friday. After a long and grueling (but awesome fun!) development cycle we’ve learned a ton. I figured an interesting way to distill our new found knowledge it would be in very short “dev tips” for developing an iPhone game. Today I start out with audio:

Compressing Audio

By the end of development our game weighed in at 16 MB. We wanted to go below the 10MB limit so users could download our game over-the-air. Quickest solution? Compress the audio. Now, we were already using some compression but we have over 60 audio files! The main crux of the problem is we want to be able to quickly compress all our audio to a certain format, build it, look at final build size, and test for quality. For this I wrote a quick script:

[code]
#!/bin/bash
rm -rf caff
mkdir caff
for i in *.wav
do
afconvert -f caff -d ima4@22000 -c 1 $i caff/${i%%.*}.caf
done

[/code]

Now for a little explanation on my setup:

  • I have a single folder (let’s call it ‘finalAudio’) with all the original, uncompressed wave files used in our game.
  • The script sits inside this ‘finalAudio’ folder as well and I run ‘chmod +x build_audio’ where ‘build_audio’ is the name of my script so I can just click on it in Finder when I’m wanting to re-export my audio.

What the script does:

  1. It removes any folder/file named ‘caff’ in the current directory
  2. it makes a new directory inside ‘finalAudio’ called ‘caff’. This is where the compressed audio will go
  3. It looks through all wav files inside ‘finalAudio’ and runs the ‘afconvert’ utility on each file and puts the resulting compressed file in ‘caff’.

I’m not going to go into the details of all the options you have with afconvert and what audio formats the iPhone supports. There’s plenty of documentation online covering that already.

Just an interesting sidenote: we took our 13-16MB game and shrunk it to 6.5 MB using ima4@22000 with 1 channel.

So we’re at the last mile (it’s a long mile..) of development on Tilt To Live. Adam and I are starting to get some pre-release buzz built up around the game as we put our finishing touches into place. With the holidays around the corner, I will be out of commission until mid January. Marketing is a whole other beast we’re trying to deal with and learn as we go.  With a market as vicious and saturated as the App Store, it’s been one challenge after another!

As many have stated, to succeed in the app store these days requires a a good bit of marketing muscle. The ‘gold rush’ is pretty much over and the app store is now similar to any overcrowded market. I’ve been reading up on marketing in general and also seeking out articles on the app store specifically. App Gamer had a very interesting piece for newcomers to the app store regarding PR and marketing.

Have a great holiday (to those that are celebrating) and see you guys in the new year! We’ll be starting off that year with a great game and hopefully many more to come!

Tilt To LiveIt’s been a while since my last post. As things started entering crunch mode and the whole holiday rush was happening I unfortunately let my blogging schedule slip as a result. It’s still going to be irregular for the next month or so as I’m trying to finish up Tilt To Live. The official Tilt To Live site has launched with a few screenies and more info though! It’s a basic info site at the moment, but I’ll be sprucing it up as time goes on. Starting to ramp up some pre-release hype around the game but it’s proving to be challenging :].

A second take on Multi-threaded asset loading

FrustrationAfter much reading, experimenting, more reading, and just plain frustration I’ve toned down the multithreading goodness on asset loading for tilt to live. The main cause for this decision was speed. I seem to have miscalculated the amount of time it takes to load images. It was somewhat of a compound problem. Firstly, loading textures with libpng was on average 4 times slower than the standard UIImage/CGContextDrawImage! I’m not entirely sure if my implementation of libpng was inefficient in some way, but it was taken from several samples and documentations on loading pngs. Secondly, loading textures on a background reduces the speed by another 2 fold!

I’ve finally implemented texture atlases, so I got a bit of a speed boost on rendering. Although, I now have a 1024X1024 textures. Using libpng on a background thread took ~8 seconds to load a single 1024×1024 png image. I put the image loading on a main thread and it reduced it to 4 seconds on average. A great improvement, but with 2-3 large textures this was still unreasonable. After doing some profiling with the basic GLSprite sample on Apple’s iPhone developer site, I decided to revert back to the UIImage/CGContextDrawImage approach and it allowed me to load 1024×1024 textures in a little less than a second. Alright, progress! I’ve reduced a 20 second load time down to about 4-5.

As a result, I removed all background texture loading from the game. To further reduce the initial launch time I see that I can defer one of the 1024×1024 atlas textures til later as it’s only needed when the main game is up. That’ll be another second shaved. This is definitely one of those times where a supposed ‘good’ thing that was implemented has come back to bite me in the ass….

unlock_lightning

Lessons Painfully Learned

The slickness of having background loading while the game is giving the user some feedback is nice, but ultimately not worth a larger load time. The discrepancy here is that on a 3G iPhone the load time is huge with background threads, but on a 3Gs it’s very fluid and barely noticeable. So if I was making a 3Gs-specific app then this is definitely something to look further into and optimize a bit more. But with the goal of trying to reach as many different gen devices as possible, I needed to compromise and give up some of the ‘flare’ for speed. Right now the target release date (or at least submitting to Apple for approval) is in January 2010.

In the meantime, follow us on Twitter and Facebook to get the latest news on the game!

…looks like I’ll be hitting a bit of crunch time in the coming weeks. Blog entries will probably be dwindling over the next month or so as I try to put the finishing touches on Tilt To Live. On that note:

No matter how much energy you feel like you have and no matter how motivated you are at seeing a project to the end, you still need to take breaks from it. Going non-stop at it for days on end is a one way street to burnout and reduced quality.

I hit my limit on Sunday where I felt if I worked on any more of the game it’d have more bugs than features by the end of the session. Was nice to take the day off and just relax to some good music and video games :). Weird how many times I’ve heard the above repeated and yet still fell into the same trap. It kind of sneaked up on me I guess. Oh well…

Tilt To Live

Almost there!

App Store Games

As I’m zeroing in on finishing Tilt To Live some of the bigger assets are coming through from Adam and the game size has grown a lot faster than it has in past few months. One of the unstated goals of mine was to keep the game under 10 MB. Why? You are not allowed to download apps, podcasts, or videos that are larger than 10 MB over 3G. You are required to connect to wi-fi in order to do it on your iPhone. Alternatively, you can use a PC/Mac and just sync the said data to your phone/iTouch, but who bothers to do that?

Having a 10MB limit on an “unlimited” data plan sucks, but I’m not here to discuss that. This limit possibly poses a constraint on iPhone developers who want their games to be widely available. I just started digging into this, but haven’t really found anything conclusive on downloading habits of iPhone users beyond a few small-sample surveys and articles.

In either case, the question I wanted to answer was:

Do you stand to lose a significant amount of potential sales/downloads for apps over 10 MB?

I decided to do some unscientific data gathering and some manual data mining with good ‘ole excel :].

The Process

I fired up iTunes and after fumbling about in the iTunes app store I was able to get to the Games top 100 free and paid section. This was actually my first time digging around in the itunes desktop app store, as I download and buy 100% of my apps and podcasts directly from my phone. Connecting my iPhone to my computer is a rare event indeed…

Not having released a game yet on the app store I didn’t have any data on hand that’d prove useful for this. I took a rather low-tech approach and just consulted the all mighty top 100 lists of the app store. I took the top 100 games in the paid list and the free list and compiled them separately to try to find two things:

  • How many 10MB+ games exist in the top 100?
  • How are those 10MB+ games distributed in the top 100?

So the caveats to using the top 100:

  • From my understanding, I’m only seeing the US top 100?
  • It’s not representative of the HUGE library of other apps that are still somewhat successful but not the over-night hit sensation that a lot of the upper rung apps are
  • I don’t have a good idea of the size distribution of games that aren’t in the top 100, so I may be missing the big picture. So any experiments seeking to find a distribution has a very limited view “window” of what is actually going on.
  • This data includes iTouch devices, but since they lack 3G this could possibly skew the data.
The Results

First, I’ll explain what I thought the results would be. Before doing any of the number crunching I hypothesized I would find that the most successful apps are under 10 MB and any app that happens to be over 10 MB would be weighted towards the lower rungs of the list.

Let’s first take a look at the free games in the app store. Below is a table showing the number of apps above 10 MB split into top N lists.

Top N Free Games

[table id=2 /]

We find in total that there are only 18 out of the top 100 free games that go over the 10 MB limit. Not exactly conclusive, but it shows that majority of top 100 free games are available over the air (OTA).  As you decrease the size of the list the number of 10MB+ games starts to dwindle naturally, but when you look at the percentages the amount of those 18 stays relatively the same until you hit the coveted top 10. The only 10MB+ free game in the top ten is Real Racing GTI, a promotional game for Volkswagen that weighs in at a rather hefty 59.3 MB!

Now how does the distribution of these “heavy” games look in the top 100 free list?

Distribution of 10MB+ Free Games

[table id=3 /]

Hmmm…The distribution of 10MB+ games is pretty even all the way up to the top, with a slight dip in the mid section.

Let’s look at paid games.

Top N Paid Games

[table id=4 /]

One thing I didn’t really account for in my original hypothesis is a difference between paid and free games. 53 paid games are over 10MB! While by a slight margin, the majority of paid games seem to ignore the 10MB rule and go for broke! Egad! This above table completely refutes my original hypothesis that most successful apps are under 10MB (Wow those last few sentences sounded super nerdy…). This is assuming you equate that success = number of apps sold * price of app = more $$$, where as in the free model this kind of breaks down. Anyway, moving on to the distribution of paid game juggernauts…

Distribution of 10MB+ Paid Games

[table id=5 /]

Interesting. While the paid app list has a majority of 10MB+ games the bulk of them live in the top 20-40 section, again, only by a slight margin. The stand out number here is the top 20 section. It appears games that are under 10MB here still win out the majority, so maybe there still is some relevance to my original hypothesis but to a much lesser extent than I imagined.

Probably not as useful, but in case you’re curious here’s a simple area graph plotting top 100 free and paid game sizes, there are some monster sized games in the top 100 so that is encouraging! Click it for full resolution.

App Store Game Sizes

The Truth Revealed?

Looking at the free games market the results decidedly point to a more “logical” trend, in my opinion, on how games are being designed. Yet, when you look at the paid games market you find that:

  • Developers don’t give a crap and make what suits them (Hurray freedom!)
  • Consumers don’t seem to give a crap either on how big it is when they are paying for a game. Maybe they even irrationally prefer bigger (in physical size, not content) games for their dollar?

While the results point to opposite trends on app store game sizes, it doesn’t really uncover if developers are consciously shooting for sub 10MB games or simply letting the chips fall where they may in either case. Could free games just not warrant enough budget to make enough assets that grow bigger than 10MB? Are free games specifically targeting “viral” game status by shooting for sub-10MB downloads to allow it to spread more easily? I also find that a good bit of the free games are also “Lite” versions (62 of the top 100 in fact). So it shows that people like to try before they buy at least. With Apple’s announcement that they’ll allow free apps with in-app purchases, hopefully things will clean up a bit. But that’s a different issue for another day.

If you’re interested in getting my scrawny little excel spreadsheet with the free/paid top 100 lists to run any fancy shmancy analytics you’re welcome to it.

significantly

I’ve made some serious progress as of late with Tilt To Live. The age old saying “I’m 90% done…” is rearing its head and  yet it feels like there’s 90% more to go! This is a bit regurgitated, but saw an interesting bit in a post on burnout and motivation at Zen Habits:

1. Achieve in increments. When you only focus on a big goal someday, it’s easy to get burned out by the daily grind. It’s like driving toward a mountain in the distance. You can drive for hours, but the mountain doesn’t seem to get any closer. And spinning your wheels gets real tiring real fast.

The solution is to give yourself a way to measure and record every little step forward you take. Here’s how:

  • Get a journal, notebook, or calendar. Writing things down is important.

While I’ve been doing the above for a while now, I’m finding the advice becoming more critical as I polish up the game and there are only smaller, less visible changes  to the gameplay or code. Along with all the milestone tracking, to-do lists, and time logs I tend to write down where I stand on the project at a high level almost on a daily basis. It gives me a good “whole picture” look at the game to see what else is coming up on the horizon or if I’m finding myself focusing too much on any single feature. Anyway, back to work… :]

Tilt To Live

It’s getting around that time when I’m spending more time working on the game as I realize how many little things need to be fixed, added, tweaked. I’ve recently given up most of my weekends now in an effort to get more hours in. I’m currently working 6 out of the 7 days a week on the game in some way. It’s mostly game programming, sometimes graphics, web development, emailing, phone calls, or getting business forms and other legal stuff squared away.

This week was a rather productive week on several fronts:

  • Got a lot of new art assets from Adam and implemented them
  • Feedback from testers started trickling in and the reaction has been positive along with tons of great suggestions/ideas
  • Fixed a lot of old bugs that were sitting in the queue
  • Improved some memory usage of textures

The week wasn’t without it’s headaches though. This completion date graph illustrates just how badly I estimated this week’s tasks:

Bad Estimates Ahoy!

The amount of tasks was unusually large for the past week, but the amount of tasks wasn’t as big an issue as some tasks taking 10 times longer than I wanted.

The biggest one was getting multi-threaded texture loading on the iPhone working. The hours I logged into getting it working is my own personal testament to how a seemingly simple task can blow up to ridiculous portions when you mention the word “multi-threading”. Had I known it’d take this long I would’ve opted for a more basic solution and leave it to a side project. The bright side is now I can load audio and graphics in parallel along with the main thread being able to continue any animations and such. It took about 20 hours to get it working and debugged, which is somewhat embarrassing haha!

Hair-pulling Threading Issues

It started with me wanting to off load the texture loading to another thread. Simple enough. I’ve done this before on other projects. It took a couple of hours to learn how to get OpenGL setup correctly to allow this. Then I discovered OpenGL wasn’t being the meanie, but a function call from core graphics wasn’t allowing me to call it from a background thread (sometimes…ugh). I researched it for a couple of days while finishing up other things, but wasn’t able to find anything conclusive. I then decided to take the leap and implement my own PNG loader using libpng as a base.  I mean really…how hard could it be? Hah…hah…ha…

Saying it was frustrating would be the understatement of the year, and last year. I usually try to avoid copy/pasting code as I like to read and understand the API I’m using so when it DOES break I’m not utterly clueless. Libpng’s interface is rather low-level and not exactly the cleanest. After reading documentation on it for what seemed forever I decided to start with an example program and modify it to fit my needs.

Let’s not forget that I’m an XCode/Unix newbie so getting libpng/zlib working as a static library in XCode was a nightmare for me. I ended up building from the source against the correct config’s and SDK’s for the iPhone to avoid the “invalid architecture” warnings. Next came actually implementing the loading. It looked pretty straight forward in all the examples I saw, except I wanted one feature I didn’t see in any of the sample code: be able to load non-power-of-2 textures onto the iPhone. All of the game’s assets are of various shapes and sizes, and several are non-power of 2. I haven’t taken the time to do proper texture atlasing and I wanted the ability to quickly drop any assets Adam sent me into the game’s folder and load it without fiddling with size alignments and the other mess.

This is where things started to get hairy because I was seeing issues crop up that weren’t necessarily from my code so I was lead astray a lot. The caveat is the iPhone has a rather special way of “compressing” PNGs. It took me a while to understand the implications of this because I could load the PNGs fine but holy shit were they rendering wrong in OpenGL! It finally dawned on me to change the blend function OpenGL was using. Much to my surprise I couldn’t find one that would give me the equivalent alpha blending that I got with premultiplied alpha’s. And I wasn’t about to go back and re-design all the assets. By this time I was pretty comfortable working with libpng and I decided to just write a custom transform function to premultiply the alpha when loading it to mimic the previous technique of loading:

Finally, you can write your own transformation function if none of the existing ones meets your needs. This is done by setting a callback with

png_set_read_user_transform_fn(png_ptr,
       read_transform_fn);

You must supply the function

void read_transform_fn(png_ptr ptr, row_info_ptr
       row_info, png_bytep data)

See pngtest.c for a working example. Your function will be called after all of the other transformations have been processed.

Alrighty, so now I can load things ~20 hours later. Talk about a huge step backwards. Doing the pre-multiplication at runtime is a trade off of convenience over speed. When it comes time to release the game I might consider doing this prior to compiling so the assets are “cooked”. But doing it at runtime adds about 1-1.5 seconds from my unscientific tests.

What’s amusing was once this was working it took 15 minutes to get multi-threading working. Now I decided to be adventurous and load the audio and graphics on separate threads from the main thread, for a total of 3. Speed tests show it’s on average no faster or slower than having both asset types be loaded in order on a single thread *Shrug*. Oh well, if the iPhone ever gets another core then I’ll be set ;). Ultimately, I now have the freedom to toss asset loading on a background thread while the game continues playing with minimal hit to the frames per second.

This  kind of thing is probably a bit advanced and overkill to do for such a simple and small game as Tilt To Live. If I have time (unlikely) over the next several weeks I’ll try to put together a complete code listing for those looking to have more control of their asset loading with libpng on the iPhone.