I had an issue where several international users were reporting that the game was crashing. As it turns out, using an NSNumberFormatter would return a weird character to display as the grouping separator. This would be all good and dandy, but the problem lies in the fact that I’m using bitmap fonts to render, and the look-up failed causing a hard crash.

In Tilt to Live’s case, this was in regards to how number grouping symbols are displayed in different locales. I use the comma to separate most of the number displays. Due to my ignorance, I just assumed ‘NSNumberFormatter’ would work with what I thought was a universal concept. Not so in some Arabic countries apparently. The fix? If you aren’t supporting localization just use the particular localization you are coding for, otherwise the formatter will use the iPhone’s language settings to pick a localization for you:

[code]
numberFormatter = [[NSNumberFormatter alloc]init];
NSLocale *locale = [[NSLocale alloc]initWithLocaleIdentifier:@”en-US”];
[numberFormatter setLocale:locale];
[numberFormatter setNumberStyle:kCFNumberFormatterDecimalStyle];
[numberFormatter setGroupingSeparator:@”,”];
[numberFormatter setUsesGroupingSeparator:YES];
[locale release];
locale = nil;
[/code]

I spent this past weekend getting retina display graphics implemented in Tilt to Live for iPhone 4. The cynic in me hates the marketing term ‘retina graphics’ because on the production side, it’s simply just a bigger image. But I guess you do need a name for it, and since ‘HD’ has already been bastardized on the iPad I guess this will do. I decided to write this post to bring a bit of awareness to some of the process of updating your OpenGL game for the retina displays if you choose to do so. I thought it’d be riddled with lots of coding work-arounds and such since our game is a 2D game with specifically sized sprites based off the resolution, but it turned out to be pretty quick and easy.

Anyway, Adam had re-exported all of Tilt to Live’s graphics at 2 times the size so the hard part was pretty much done. It was made much easier by the fact that he was using Illustrator and vector graphics, so there was zero need to redraw or redo any assets. On the coding side of things, I feared I’d be spending hours re-tweaking game code because a lot of constraints and boundaries were hardwired to image width’s and heights (bad I know). But in the end, I luckily avoided all of that. Most of my sprite rendering code is encapsulated in a SpriteImage class with width/height properties. I made a simple modification to those properties where the returned width or height was multiplied by a ‘renderScale’ variable that represents the scale of the display. In effect, the width/heights would return whatever the game was designed for at the 480×320 resolution, but under the hood would be using a larger texture.

For non-openGL apps, they get a few things for free on the retina display such as font rendering and UI scaling, but how do you set up your graphics window to support retina graphics? A quick look over at the apple docs shows how to setup your OGL context to scale by a factor of 2. When it came down to implementing it, just doing:

[code]
self.contentScaleFactor = DisplayScale();
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);;

//..continue setting up framebuffer
[/code]

…got me rendering 4 times as many pixels. The game still looked exactly the same since I hadn’t replaced the graphics yet. What is DisplayScale()? It’s simply a wrapper I wrote:

[code]
CGFloat DisplayScale()
{
return [UIScreen mainScreen].scale;
}
[/code]

Now if you’re using UIImage to load your textures then you’re in luck for updating graphics. Adding a file with the ‘@2x’ suffix will automatically be loaded on an iPhone 4 instead of the normal resolution. For example, myImage.png and myImage@2x.png live side-by-side in your bundle, but on the iPhone 4, it will load the @2x one. I had been using libpng directly to load textures a while ago, but opted to revert back to UIImage for performance reasons.

Now this is all well and good if you’re using separate png’s for your images. But to improve rendering speed and memory consumption a lot of times one will use spritesheets. Having a @2x sprite sheet is nice if the spritesheet generator you are using puts them in the same relative positions. As for me, there were a lot of unused sprites from previous versions so I took the time to clean up things. This was a bit time consuming as I had to verify which images were still being used and which ones weren’t. The ‘@2x’ trick only works on UIImage, so if you have any supporting files (font descriptions in particular) that are needed in conjunction with the graphics file you’ll probably have to write your own ‘@2x’ searching and loading for those particular assets, which is no biggie either:

[code]
NSString *path = nil;
NSString *resource2x = [fontName stringByAppendingString:@”@2x”];
if(IsRetinaDisplay())
{
path = [[NSBundle mainBundle] pathForResource:resource2x ofType:@”fnt”];
}

if(path == nil)
{
path = [[NSBundle mainBundle] pathForResource:fontName ofType:@”fnt”];
}
[/code]

As for other caveats? Fonts were a big one depending on how you export and render them. I’ve been using BMFont to do all my font exporting. It’s a great tool but a little ambiguous when it comes to font sizes. There’s a ‘size’ field, but it refers to character height. Does doing a doubling of character height garuantee exactly twice the width/height]? What about the option for ‘line height’ [unchecked character height? I ended up using line height, since that’s the option I used initially when making the fonts. It worked pretty well. I tweaked my bitmap font rendering a bit and it supported retina graphics shortly after without having to change game or UI code. There was a slight issue with some lines of text being rendered 3-4 pixels lower, but I didn’t spend too much time investigating it as the issue isn’t noticeable in normal use.

Another caveat has to do with rendering GLPoints. Be sure to scale GLPoints when setting glPointSize() if you’re using that functionality at all. Tilt to Live uses it extensively to render enemies faster instead of quads.

It’s been hellishly busy as of late, as I’m knee deep in Tilt to Live HD.  Now on with my quick blurb:

This tip is kind of a “duh” much in the same way version control software is for most developers. The thing is I still meet a lot of developers who don’t use any form of version control. And automated builds simply weren’t even in my own tool set initially. Mostly because my build steps for projects never scaled to the complexity required to build like an iPhone application. And it wasn’t even complex. It was just a matter of remembering which command line parameters to use and which provisioning file to include and to zip it up all tidy and neat.

Now with XCode’s build and archive command a lot of this is simplified with a GUI, but that’s the crux of it. It still requires you to go through several clicks to send a build out.

My setup is pretty simple by using a makefile and the xcodebuild commandline tool. xcodebuild just allows you to build projects from a commandline very easily. Mix that with a few basic unix commands, agvtool, SVN and you have a primitive but simple build pipeline that you can execute with a single command and not thing about anything else. I’ve been using it throughout Tilt to Live’s development and haven’t had a need to really look elsewhere since it accommodates exactly what I need to do: not screw up build submissions or beta builds for testers.

Over the months my makefile has grown to include a few other ‘targets’ for faster iteration during gameplay tweaking, but the 3 essential ones were:

  • build – this just builds my app for ad-hoc distribution into a zipfile named ‘appname_versionnumber.zip’ and a debug symbols file next to it. It then moves these two into a builds folder where I keep all my builds. It works in conjunction with the agvtool so that it increments the build number and submits the new version to SVN.
  • appstore – This target does the same as ‘build’ except it builds with the app store distribution settings.
  • clean – just wipes all my intermediate object files and build temp folders if I want to build from scratch

Below is just a snippet from my current build target. It builds the projects, moves the app files and provisioning files into the current directory. Zips those two up and copies them to a build directory with the debug symbols.

[code]
build:
cd $(PROJDIR) ; agvtool -usesvn next-version -all
xcodebuild -project $(PROJ) -target Tilt_To_Live_HD -configuration Distribution

#move app files into build directory
cp -R $(DISTRODIR)/$(APPFILENAME) $(APPFILENAME)
cp $(PROVISION) $(PROVFILENAME)

#zip up the app file and move debug symbols
zip -r -y -q “$(BUILDDIR)/tilttolivehd_`cd $(PROJDIR) ; agvtool vers -terse`.zip” $(APPFILENAME) $(PROVFILENAME)
rm -rf $(APPFILENAME)
rm -rf $(PROVFILENAME)
cp -R $(DISTRODIR)/$(DEBUGSYMBOLS) “$(BUILDDIR)/tilttolivehd_`cd $(PROJDIR) ; agvtool vers -terse`.dSYM”
[/code]

I wonder if the xcodebuild tool has some commands for automating the ‘build and archive’ command. That would simplify my targets even more.

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.

While I was working at a day job for the past couple of years I was gobbling up any info I could find on going fully independent and the what it takes not only from a business perspective, but what you have to change about your personal life, ideals, and expectations in order to make it sustainable. One of things that stuck out a lot was managing my burn rate. Minimizing the amount of money leaving my account wasn’t just a matter of not buying a Starbucks coffee (I don’t even drink coffee, but you get the idea). It required some fundamental changes in the way I thought about money and how it related to my daily life. Jeff Tunnell I think articulated it very well in his article, where he talks about “Right Sizing Your Life“:

The bottom line is that you cannot live downtown San Francisco, drive a Porsche, have three kids, eat out every night, have Starbucks two times per day, charge up the credit cards, and live the way most of society tells you to. If you want this stuff, start coding in Java and go to work for IBM. But if you want to enjoy your work, feel creative every day, and make games for a living, you will have to pay a price.

Adjusting Your Daily Life

It sounds pretty obvious and seems straightforward. But it’s definitely easier said than done. The biggest problem being that if you are working a day job, if a decent one at that, you can afford a lot of extra expenses. Having a “steady paycheck” at a day job numbs that feeling of loss when I spent money. I would always spend within my means, but when my means don’t match up with what my “means” will be by the time I’m independent, I imagined I’de be in for a tough transition.

I tried all the obvious things: Stop eating out. Stop buying food/drinks at bars every weekend. Start cooking at home. Start watching less TV (canceling cable). Doing any of these cold turkey was a difficult feat. But like any sensible diet/exercise plan you should do it in moderation until you’ve achieved your goal. One of the things I noticed is when I find myself hanging around friends and socializing a lot, spending went up. It’s an obvious and natural occurrence, but I would think most people believe they are in control of how they spend their money. But in fact, at least in my case, where and how I spend my money is heavily influenced by what I am doing and with whom. You go to bars, movies, play games, eat out with friends. That’s not to say you should become an anti-social either. You just need to plan accordingly and figure out a way to fit your new goals in with your current social circle. For me, it became less of a spontaneous thing and more scheduled. If I knew I had plans later in the week to go out, I spent/saved accordingly to make it happen if it was possible.

Technology to the…rescue?

I also tried a lot of money management software with mixed success. Mint was a popular choice and one I had used initially. It’s great for tracking where you’re money is going. But it’s biggest strength may be the weakest link in trying to change your spending habits. It’s a passive way of keeping track of your money. You have to be vigilante in looking back on what you spent after the fact to see why the numbers worked out the way they are. I decided to try a different approach by creating a habit of logging expenses as I went throughout the day spending money. Since I had my iPhone with me everywhere I went, it seemed natural that there’d be an app for that.

I  used Spend [iTunes] to keep track of my spending but also try to enforce some sort of budgeting. When I think about it, the idea here isn’t so much as to just “keep a log” of what I’ve spent, but to encourage a habit where the act of spending money requires me to reflect on it for at least the briefest moment. Spending with a debit/credit card is easy, but when I have to pull out my phone, load up the app, type in a description and price, the entire time I’m thinking about the act of spending money. It becomes a bit more painful, similar to spending real cash. This had a much better impact on my spending habits than Mint did. I could more visibly see in real-time where my spending was heading and how much room I had left in my budget. I become much more aware of all the “small things” I would spend money on throughout the day like vending machines, snacks, sports drinks while working out, etc. The specific app I use isn’t important, it’s more about developing a habit to be conscious at all times of where your money is going.

Keeping At It

Having friends and family that support your goals goes a long way as well, not only in your spending habits but also in what you consider good ways to spend your free time. Fast forward a few years later, my day job is making indie games, my views on what I feel is important financially and personally has changed a lot and I feel a lot less stressed out about money in general. Just by trying to reduce my burn rate for several years I have a very clear picture of what I need in terms of finances in order to make this indie business sustainable. So in essence, I have a very good gauge as to whether I’m in trouble or not relative to how much I’m taking in. Also in an effort to reduce my costs even further, I moved back down to the deep south (Alabama). Living near DC is pretty expensive. It’s a pretty big move leaving DC behind because I loved that city. But in the end, being closer to family and life long friends in the south was a great bonus to saving a lot of money on living costs. I consider myself pretty mobile at this point in my life being single with no kids or spouse to look out for; so up and moving may not be an option for everyone.

Stepping outside the “rat race” is more than just becoming independent. You have to be willing to fight the pressure from those around you to change your thinking. Managing and minimizing your burn rate is one of many aspects of making the transition from “employee” to “self-employed”. Not the most detailed post, but hopefully will give those working-by-day-indie-by-night a few ideas to step a little closer to full-time.

When your profession empowers you to design literally just about anything, it’s easy to rationalize just about any game design decision. Hell, I somehow managed to rationalize that our new power up for Tilt to Live have a screeching hawk sound effect. Bad idea? You’ll have to wait and see.

When Adam and I are working on design details for how a particular system or game mechanic will work, we bring a lot of assumptions to the table of how we think people think. And those assumptions are sometimes rooted pretty deeply so it’s hard to get on the same page. What do we do then? We get into an all out brawl. Ok, not really. We usually turn to our ‘beta testing’ group to do some observation of how they play and react to our design decisions. Our group isn’t very expansive at the moment as most of them are local friends so we can bring them in and have them play our latest builds. Keep in mind I use the term ‘tester’ for anyone that seriously runs the game through it’s paces and those that play it really quickly to see how the game works. Now all this is the easy part. You have a conflict or issue figuring out some detail of a design you go to play testing to try to gather some data. Simply enough. If you aren’t doing at least this, then you’re crazy awesome at game design and you should stop reading. Now. Really.

Doing it honestly.

Like I said before, it’s easy to rationalize any creative decision. It sometimes becomes even easier to rationalize a creative decision in the light of data.  “See? He did notice that you can only have pick up at a time active!” or “See? He didn’t even notice the limitations of the pick ups because he just runs through them blindly!” You have to try to stay objective as possible. You have to try to get in the shoes of the player and see what they see. Ideally, they are talking to you the entire time as they play giving you verification that your hypothesis is either incorrect or correct. Having worked on a single project a long time, the decisions you make on it almost take on a personal weight. When you find that your idea doesn’t work, you can take it personally if you’re not careful. This can become dangerous not just for your own mental well being, but testers/friends can pick up on it and not tell you what you need to hear.

One tip I found helpful in reading my data and separating myself from my idea is: Don’t think of why your idea will work. Think of why your idea won’t work. It can be seen as a negative way of going about things, but only listing the positive doesn’t help you analyze your decisions. You become blinded by the ‘happy path’ of when your idea is executed inside a narrow scenario, ignoring a sometimes large problem in the shadows. Uncovering the weaknesses in your design is far more telling than a huge list of positives. Save the positives for the “back of the box” :).

Doing it early.

One of the things that still gets me today is trying to send out builds of our game as early as possible. I always keep saying “just one more day and I’ll have feature X completed or bug Y squashed”. I have to remind myself that our testers aren’t our ‘true’ audience. Yes we want to make them happy and have fun. But better to have your helping hands tell you your game idea is utter crap than to find out it is utter crap 3 weeks after release. This one can be rather painful because you’re fully aware of all the gaping flaws in the code, art, and mechanics and you don’t want to show your work in an incomplete state. Not to mention, it’s hard to explain to your testers why the player sprite is flickering about as if it’s having a seizure whenever they press ‘jump’. Well do it anyway. And get use to it.

We’ve been getting better at this through all the game mode additions we’ve been doing to TTL. With our latest mode, Frostbite, we’ve had play testers in very early in the iteration of the game mechanic phase. They’ve seen the game grow and each step of the way have provided extremely good feedback on helping us balance the game. The actual game mode wasn’t even fully functional when we started playtesting. So what did we get out of it? We focused on the feel of the movement, controls, enemy placement. All minor things that I would spend tedious time tweaking on my own. With each new iteration we tell themwhat was new in that build and have the testers focus on it instead of being overwhelmed by “play this whole game mode and tell me what you think.” One thing to keep in mind is beta testers are there for feedback. Try not to let it turn into a ‘designed-by-committee’ ordeal. Or maybe you want to…but I’m a control freak so that’ll never happen ;).

Doing it often.

This can be a double edged sword. From my limited experience, testers can sometimes be seen as a limited, nonrenewable resource. You may have a completely different group of testers by the end of the project than when you started. I had this idea of being gung-ho about testing early so I would send out weekly builds to everyone very early in the development process. The problem? Tester fatigue. When the deltas between versions is very minimal, testers may not be interested in a weekly build. As a result, I spaced out the test builds in early development to be a little more rare so that testers had time to recover and were excited to give a new build a try. As release  day got closer, this feedback loop shortened as we approached daily, sometimes hourly test buids.

In the end, no matter how you approach getting feedback for your game, it is almost always is beneficial to your game.

This post is part of iDevBlogADay, a group of indie iPhone development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web siteRSS feed, or Twitter.

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]