This following post is probably going to be useful to an extremely niche audience: anyone developing a multi-user iOS app that has a GAE backend. I’m currently working on Outwitters and debugging turn-based games on the local dev server (dev_appserver.py) is really quick and painless. The problem arises from the nature the game. It’s a multiplayer game, and as such, requires multiple users to function. You can only go so far with creating ‘mock user’ accounts, and fake data populating your local server. With each build I always find some sort of issue that the alpha testers stumble across that may not be server-related but the gamestate that the “production” server is holding is something I want to grab and debug with locally. Wouldn’t that be nice?

So when you run a local dev server the command is pretty simple:

[code]

dev_appserver.py pathToCode

[/code]

Not bad. Now if you want to access it on your machine you simply do an http request to localhost:8080. The problem comes in when you’re developing for a mobile device. The dev server is no longer at localhost but on some local LAN IP. That’s a pretty easy fix too:

[code]

dev_appserver.py –address 192.168.1.x pathToCode
[/code]

Now in your iOS app you can send requests to a local server. We’re in business, awesome! So you want to download the data from your hosted application over at appengine.google.com? Pretty simple. Uploading it is pretty straightforward to if you use the –url option with “appcfg.py upload_data”.

Now this is where I ran into problems, and I couldn’t find a clear cut answer as to why uploading data to my local dev server was simply not working. It would ask for credentials, and no matter what I put, it would fail. Hopeless. I used all sorts of combinations of my local address and ports for the –url flag for appcfg.py and tried countless combinations of any of my known logins for both appengine and my local dev machine. I then decided to go back to basics, and follow their instructions exactly. I downloaded the production data as documented. Then I launched a clean dev server with no command line options. It worked as advertised! I had all the data frolicking about inside my dev server, but I couldn’t access it with any of my iOS devices. Without the address option, the dev server would launch with localhost as being it’s address, and no other device could connect to it.

So after banging my head on the keyboard for a couple hours, and not being able to find any answers as to why upload_data only works to a local dev server if you’re running on localhost, I found a round-about way of getting production data into my own iOS friendly dev server:

  1. Download the data as per the documentation
  2. Now launch  dev_appserver.py, but this time declare a datastore path as a command line argument. This is the –datastore_path= option. Also run it with a –default_partition of “” (empty string), to mirror production’s data.
  3. Now that you have a dev server running on localhost with a defined datastore file, upload your data to your dev server with appcfg.py (by using the –url option pointed to localhost).
  4. Once uploaded you can now shut down that server.
  5. Now run a dev_appserver with the commands that you usually run with (the –address flag), but add a –datastore_path pointing to the datastore file you used in step 2.
  6. W0ot!
A lot more cumbersome than just doing a simple download/upload routine to test stuff locally. Of course, I may be missing something entirely as I’m still relatively new to GAE, and there may be a way to do this with a local dev server that is running on an actual LAN ip instead of localhost, but I haven’t been able to find it. Hopefully this will prove useful to those using GAE for their iOS apps as well, or they’ve found a better way to do this and can leave a comment :).

About two weeks ago I mentioned I was looking into using the open source library, gameswf to integrate into our little 2D engine for iOS. I was at the point where I needed a UI solution for Outwitters, and I had a few options:

  1. Keep doing what I was doing with Tilt to Live and create the UI by handing coding everything and procedurally animating it
  2. Create a UI editor to help automate some of the UI features I had created in Tilt to Live
  3. Look into gameswf and see if I could go for the whole she-bang and just use Flash for the UI.

I’m happy to report the gameswf seems to be doing just dandy on iOS. When researching, I was hearing a lot of complaints on performance and compatibility (it’s only compatible with actionscript 2.0), and if you’re using a lot of complicated vector shapes you can bog down the FPS. Well reading the post date on a lot of those articles I found that some were pre-dating the 3GS! So in the end, I just put aside a week to mess around with gameswf on an ipad 2 and try to convert some of the ‘hand coded UI’ in our prototype to using flash.

Exhibit A

Just a disclaimer, all that you see in this video is a work-in-progress and extremely early. It was mostly a mock up to play around with the UI.

So in the video you see the main menu with the Outwitters logo, some buttons, a blue blade, and a background illustration being animated. This is entirely made in flash with pngs and some static text as buttons (just a full screen swf). As I press a map to load a pop up blinks into existance asking if I want to resume a previous game or not. This pop up doesn’t have any external bitmaps or pngs in it, it was made as vector shape rectangle with curved corners and some static text (which actually are bitmaps, but this is handled internally in gameswf). And finally, the mock up game board screen you see a flashy banner come across the screen announcing the player’s turn and shimmering, and then pulling away when the player taps the screen.

The animations weren’t anything too special as my flash skills are pretty horrible these days, but hopefully one can see that in the right hands this can be an incredibly useful tool to making games look that much prettier and be more engaging.

The best thing that’ll come out of this, is now the artist, Adam, has a large amount of creative control of how the UI will look and feel. Before it was heavily on the programmer side to make things work, and the fidelity suffered for it.

The Downside

Now for the things that might be problematic going forward:

Memory

Nothing has changed about this as far as I know, but images are required to be sized at powers of 2. When your working with the lower level api’s this isn’t a limitation that is difficult to overcome because you have so much control over what’s being loaded and how it’s organized in memory (for example, texture atlases). With gameswf, images are handled internally and they do 1 of two things:

  1. If the image is a non-power of 2 size, it will be resampled into a power 2 size using a software-based resizing algorithm. This can be a rather expensive performance hit if you don’t take this into account. The side effect as well is images that go down this pathway end up being rather blurry
  2. If the image’s height and width are a power of 2 then it uses the image directly.

My current solution? Just making image sizes a power of 2 before importing them into the Flash library. Yea it’s a lot of wasted space, but given how the UI functions currently, they aren’t long-lived objects so the memory is freed shortly after the user dismisses the screen or moves on. Of course, in the actual gameplay screen any flash-based UI elements have to be optimized. Sprite sheets aren’t exactly feasible in the traditional sense, but you can emulate sprite sheet functionality in flash by creating a movie clip that is masked differently on each of it’s frames. It’s tedious, but I imagine if you’re needing the extra memory savings this could be the way to go. There are a few other memory saving techniques I haven’t explored, like shared libraries that might provide some benefit as well.

In any case, if you’re targeting really low hardware (3G and below), you’ll most likely run into memory issues. The iPad 2 handled it just fine, but I imagine once I get down to the 3GS model and iPad 1 I’ll have to tighten my belt on the memory usage a bit, but it certainly seems doable.

Resolution

I had spent about a week coming up with a small body of photoshop scripts in conjunction with TexturePacker to help streamline our process for creating assets at different native resolutions. The upshot is we have the assets. The downside is now they can’t be used as-is. I don’t have a ‘swf generator’ to generate iphone, retina, and ipad resolution swfs. So right now it’s looking like it’ll be a completely manual process of us creating separate swfs for each platform/resolution. Of course, if our swfs were 100% vector graphics, this wouldn’t be an issue :).

I’ve pondered some possible solutions, but haven’t experimented with any yet. One idea I had after browsing some of the source was using the ‘scaling’ feature of gameswf to scale the rendering of swfs, but inside the actual flash files do some actionscript magic to display the correctly sized graphics in the UI. Not sure how much tedium this would save in the long run without some sort of automated way to do this. On one hand, Adam or I would be laying out 3 individual flash files to be used. On the other, we’d be laying out a single flash file but then I would be scripting the resolution changes in the file itself. I would have to come up with some sort of ‘utility’ style movie clips in the flash library to help with this, but maybe it could work better than managing 3 files for every UI screen?

Scalability

Given the tests I’ve done so far, there’s nothing there that has lead me to believe that doing a commercial quality game on the iphone/ipad with gameswf isn’t possible. In fact, I’m sure it’s probably been done by now and it just hasn’t been talked about? Which is kind of strange, considering how awesome it is. But maybe that’s just me geeking out. This isn’t so much as a concrete downside as it is more of an ‘unknown’. My concern is once we’ve got a lot of in-engine animations/particles running how will it fair with a flash player running the UI. The other caveat is Outwitters lends itself really well to this type of setup as it’s not a very fact paced game. So this solution might only be feasible for particular types of games (in the same way that using UIKit and CoreGraphics instead of OpenGL is feasible for some types of games). I guess only time will tell.

The Upside

Some of the positives of using gameswf particularly:

Lazy loading of images

When a bitmap is being rendered inside gameswf, the texture isn’t sent to openGL until the first time it is drawn. It’s a nice thing to know. We can kind of ‘stuff’ our flash files with image assets and not worry about them taking up tons of memory at runtime as long as we don’t render it all at once. This is useful for HUDs that are themed, in our case, by team colors, shapes, and logos. A point of caution is the the image *isn’t* unloaded from memory (even if you call an unloadMovie() from ActionScript on an externally loaded flash file).

Auto-rotation support seems feasible

Prior to this development I haven’t really considered doing anything too extravagant with support for auto-rotate. If we did support it, it would simply switch to the correct orientation and be done with it. But now it seems pretty trivial to have the UI do a fun but subtle animation as it stretches, squashes, or moves over to accomodate the different screen real-estate. It’ll be a ‘nice touch’ if we get that working.

It isn’t an all-or-nothing setup

Giving the sample project of gameswf for iOS a quick look it seemed at first that running flash was an all-or-nothing deal. It was initializing in the main method and pretty much took over how things were rendered onto the screen. This part was time consuming but after experimenting around with it a few days, I got gameswf to play nice with my already established framework for game screens and UI. Each screen in our game is just a subclass of a ‘Screen’ class that houses ui widgets and any logic particular to that screen. I was able to refactor a few things, and now I have just a subclass called ‘FlashUIScreen’ that takes in a flash file name and a ‘controller’ class as constructor parameters. It now functions and renders identically to anything I previously did. The point being, that if the need arose for something to render in-engine (perhaps using game assets already in memory for some sort HUD) I can still fall back to my previous method of hand coding UI. Hopefully that will be the rare exception than the norm.

Some Things To Know

It’s been a quick 2 weeks since I decided to investigate it and there’s still a few things left to answer, but currently I’m moving forward with the assumption we’ll be using gameswf for this project, and that is a fun thought to entertain :). For anyone else that is curious on getting gameswf up and running here are just some things I ran into while working with it:

If you’re loading separate movie swf files you’ll need a separate gameswf::player instance. I first went with the approach of having a single player and calling load_file() on anything I needed to render because I didn’t completely understand the relationship between a player and a gameswf::movie isntance. But the player tends to house the actionscript VM for a “root movie”, so loading 2 movies from a single player gave me some wonky actionscript behavior.

If you delete all the gameswf::player instances at any point in time, the library goes through a ‘complete clean up’ phase of gameswf. This game me some issues when I would transition from a main menu to an all OpenGL view (no flash UI) so the swf players were delete, and when I went back to a flash-based menu the app would crash with an EXC_BAD_ACCESS error. I got around this by instantiating a single gameswf::player instance that didn’t load any files and is held in my singleton service-based class. It’s only ever deleted when the app shuts down.

Getting the GL state setup correctly was probably the most time consuming part. The library worked great in isolation, but when combined with the framework I was working with, there were all sorts of states I had to track down in order to render a flash file and still be able to render openGL correctly right after. Below is just the snippet of the code I wrapped around a flash movie’s display() method.

Somethings to note, it likes a blank projection matrix (had to reset it to an identity matrix) and you have to disable a few client states in order to render flash properly. Once, you leave the display() method you need reset your gl color, blend functions, and possibly any other states you have may used with the assumption that they are enabled:

[code]
const int w = GetDisplayWidth();
const int h = GetDisplayHeight();

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
_movie->set_display_viewport(0, 0, w, h);
_movie->set_background_alpha(0);

glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
_movie->display();
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
SetGLColor(1, 1, 1, 1);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

[/code]

And with that, I’m off to do some more work on Outwitters. Adam and I just played a few games over lunch and I actually WON. Mark this day, for this is the first day I didn’t get completely rolled in my own game.

As we’ve announced on the OML site, our new game has a name: Outwitters. It’s been quite busy for the last couple of weeks, but I’m loving it. Being able to tackle new problems and going outside my comfort zone in terms of game development has been pretty fun so far. I’ve never coded a turn-based strategy game from start to finish, so I’m having to learn a slew of new concepts and design patterns to help mitigate the complexity of the game’s rules. I’m usually coding physics-based dynamic gameplay where things are far less rigid and you are coding a vague system of rules the user can easily manipulate.

A hurdle I recently got over was managing the complexity of all the animations Adam is churning out. We have quite a few frames of animation that needed to be edited in bulk with all the color permutations and classes. With the help of Blitzmax, Photoshop scripting, and TexturePacker, I set out to write a simple character animation editor that allows us to edit one animation and apply it to all the different team colors and different resolutions (iphone,retina,ipad). Also when new units are done and ready to be animated, the editor automatically generates stock animations for each new character so we’re only going in and adding in a few frames and tweaking timings in some of the more elaborate animations.

The art pipeline  process for characters has become:

  1. Run a photoshop script to process all PSD files to convert layers into separate pngs in set folders.
  2. Run a command line script (written in blitzmax actually) that takes the pngs and automates TexturePacker to spit out spritesheets and json files for all the different resolutions into a designated folder
  3. Open Character editor, and if it’s a new character go to file->initialize character and all the stock animations and animation files will be generated based off the pngs and json files in the chosen folder
  4. do any manual edits to animations in the editor itself
  5. File->save and go celebrate since you’ve just processed a couple thousand files in about a minute.

I probably could have automated step 3 itself, but since one of us is usually going straight to the editor to edit the new character, it’s just an extra click so I took the lazy route there.

 

We hit another major milestone earlier this week with the fully playable ipad prototype finished with our first iteration of the UI/Interaction. So now we can get a decent number of games played. This’ll hopefully help us get a good amount of feedback on balance, game rules, and how usable the game UI is, while working in parallel on some of the ‘shiny stuff’ for the game. Lots of progress in the past week! Now I’m going to scurry back to my cave as there is still lots of science left to do…

 

Tilt to Live HD’s Viva la Turret mode is now live and people seem to be enjoying it. One of the bigger hurdles in this prior update was getting in app purchases to work the way we wanted them to without violating the standard user experience of IAP. I figured I’d share how I went about solving this for Tilt to Live HD specifically. We had a few business goals in mind:

  • We wanted to maintain parity with the upgrade model we went with on the iPhone, which was a simple in-app purchase to get the new mode.
  • We still wanted to maintain the ‘demo then upgrade to full version’ packaging of Tilt to Live HD for a single price, as we still believe it appeals to a certain type of gamer that wants a more traditional model for buying a game.

In a way, it seems our two goals were at odds with each other. We wanted players to have an optional upgrade, but at the same time we didn’t want the ‘full version’ to break down into “meh..it’s kind of the full version..but not really”. Our solution was to treat it as a paid upgrade for existing users, but bundle the new mode in with any new customers who bought the full version of Tilt to Live. The caveat being we did not want to break it down into some sort of ‘store’ list, where a user could inadvertently end up buying the wrong version and be double charged for overlapping content. We were pretty proud of the IAP integration in HD where it was a relatively seamless experience that didn’t involve any UI that required a “store” button. We simply showed you the gametype option and it was locked if you didn’t have it, and unlocked if you did.

With the additional new mode, we now had 3 basic states you could possible be in.

1. You have the demo version of Tilt to Live HD, so the gametype select screen is pretty standard and you see 1 in app purchase that includes everything:

2. You have the full version of Tilt to Live HD prior to February 8th. The gametype select screen should show you just the small IAP for the single Viva la Turret game mode:

3. You have the brand new full version of Tilt to Live HD, so everything is unlocked:

Now this sounds all well and good and pretty straight forward when I first considered it. Then came the technical details:

  • The behavior of IAP is such that it mirrors functionality like App Store purchases. If you’ve ever bought that IAP before, you can buy it again, but a pop up will notify you that you already own it and are downloading it again for free.
  • If a person has never restored, then simply checking what modes in the client are unlocked is sufficient and is the path of least resistance.
  • If a person has restored/re-installed, there is no API from Apple to determine if a person has already bought a piece of content before they try to buy it again, which could result in angry customers being double charged if they were in state #2 (pictured above) but have re-installed and ended up buying the full version again as if it was in state #1 (pictured above).

Essentially, when a prior customer re-installs our game for whatever reason, there was no way for me to determine whether they never bought the old full version and we should upsell the entire new full version, bought the old full verison and we should upsell just the game mode, or if they already have the entire thing unlocked (either by buying the old full version + the turret IAP or by buying the new full version that includes everything). Confused yet?

The riskiest thing was that I did not want to have a situation where a person could inadvertently buy the entire brand new ‘full version’ IAP when all they needed to buy was the small turret IAP. With the StoreKit API lacking any sort of method to determine a user’s purchase history, and with Tilt to Live HD not using any sort of server solution to track receipts,  I was running out of ideas. Then I got the idea of experimenting with a little “hack” to simulate the same IAP experience.

When a user taps on the ‘buy’ button for any IAP in the game I decided to instead force it to restore purchases all the time. Using a small collection of state variables when a restore was finished I would check to see if what they were purchasing was in line with what was restored:

  • If so, do nothing and give a standard dialog showing they restored successfully.
  • If it was in conflict, let them know nothing was purchased but their previous items restored. I would then refresh the upsell screen showing what they could really purchase.
  • If there was no conflict and they, in fact, don’t own any part of the IAP, then I would immediately push the purchase through. The great thing here is since it happens right after the restore, the user is never prompted for their password again since they already did so during the initial tap of the buy button to trigger the restore.

When going about implementing this I had a few false starts and dead ends, but after re-reading the documentation and a bit of experimentation I finally grokked most of the restoration API from StoreKit.

There are two methods involving the end of restoring tranactions. There is one that is called at the end of each IAP item restored:

[code]
-(void)restoreTransaction:(SKPaymentTransaction*)transaction
[/code]

And then there’s a method that is called when none, or all IAP items have been restored:
[code]
-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
[/code]

The former I left alone to act as it normally would under any restoration of transactions. The latter method, I modified to behave as an ending point if the user really tapped on ‘restore purchases’ or a beginning point to analyze what was restored and to continue with the purchase if needed. Below is the method in full in case you’re curious:

[code]
-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
if(iapTransactionState == kIAPTransStateRestoring) // restore as is.
{
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseRestoreSucceededNotification object:self userInfo:nil];
}
else if(iapTransactionState == kIAPTransStatePurchasing)
{
if([self isContentUnlocked:purchaseItemID])
{
// if it’s been restored or unlocked already then no need to do it again.
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseTransactionAlreadyHaveItemNotification object:self userInfo:nil];
} else {
//…unless we’re already in some half-bought state (full -> full+turret)
bool makePurchase = true;
if([purchaseItemID isEqualToString:kIAPFullAndVivaLaTurretID])
{
// if after restoring we found the player purchased the full and viva separately
// don’t go forward with payment for the bundle.
if([self isContentUnlocked:kIAPVivaLaTurretID] || [self isContentUnlocked:kIAPFullVersionID])
{
makePurchase = false;
#ifdef DEBUG
NSLog(@”bundling purchase error”);
#endif
}
}

if(makePurchase)
{
// continue with the purchase
SKPayment *payment = [SKPayment paymentWithProductIdentifier:purchaseItemID];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else {
// send a bundling error message
// or a restore complete if they have entire bundle
// because they purchased it separately (upgraders)
bool hasBundle = [self isContentUnlocked:kIAPVivaLaTurretID] && [self isContentUnlocked:kIAPFullVersionID];
if(hasBundle)
{
#ifdef DEBUG
NSLog(@”has complete bundle, no purchase made”);
#endif
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseTransactionAlreadyHaveItemNotification object:self userInfo:nil];
}
else
{
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseTransactionAlreadyHavePartialBundleNotification object:self userInfo:nil];
}

}

}
}
#ifdef DEBUG
NSLog(@”restore done”);
#endif
// [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseRestoreSucceededNotification object:self userInfo:nil];
}
[/code]

I can’t say this is the most ideal solution since I feel it’s using the StoreKit API in a slightly unorthodox way, but it works well. So this is one way of implementing a ‘paid upgrade’ for IAP items. If we were selling more items in a more ‘freemium’ type model it might’ve been a good idea to generalize the above code to handle upgrades for any item, but since Tilt to Live HD’s model is a one-off IAP I didn’t bother generalizing.

I’m still in the middle of finishing up our Co-op mode for Tilt to Live and coding in the last odds and ends to polish up the UI. The gameplay rules have be finalized and it’s been a hoot to play. Yes, I said hoot. We’ll be playtesting the mode in the coming weeks to do any minor tweaking to the physics and balance.

The wireless P2P GameKit API has been pretty cool to work with. It certainly takes a bit longer to get something tangible out of it because it’s a relatively ‘invisible’ piece of the iOS SDK  (as opposed to Core Animation, UIKit, and the like). Yet there’s always something inside me that goes “that is so damn cool” when I finally see a game running on two separate devices and are interacting with each other.

I’d like to write up a mini post-mortem after the co-op update is done looking back at adding real-time networked play to an iphone game. But for now, the biggest hurdle was realizing that running with the GKPeerPickerController  limited you to only bluetooth. The docs weren’t 100% clear on this and I was beating my head on my desk seeing people claiming GameKit worked over Wi-fi with no issues and I couldn’t get any device to talk to each other without bluetooth. Couple that with a faulty router setting keeping my iDevices from connecting to each other and it was a painful couple of days. In any case, let it be known, that if you wish to support local Wi-Fi and Bluetooth transparently you’ll need your own custom UI outside of GKPeerPickerController for clients connecting a host.

Oh, and the utter joy I experienced when I realized I had to change zero networking code to have it work over w-fi was indescribable. I think I fell in love with GameKit at that point since I was anticipating  a day of refactoring, integrating bonjour directly, and whatever else I had in mind to keep the game-level networking code intact.

For anyone thinking about doing some real-time multiplayer game on the iPhone, the biggest problem you’ll probably face is interference, followed by throughput (when dealing with bluetooth anyway). iPhones are jam packed with so much wireless technology that it seems if the wifi or 3G antenna so much as thinks about sending or receiving data, bluetooth communication suffers horribly.  I’ve had many a game end in death when I received an e-mail or text during gameplay. We originally intended on supporting nothing but bluetooth, but given this type of wildly varying performance we needed to have a fall back solution that was a bit more reliable. Thankfully, GameKit made it easy. While I was hoping I wouldn’t have to code up a custom UI (pictured above) because of GKPeerPickerController’s magic, in the end it added more robust functionality, as well as felt a lot more integrated into the game.

I’ve started holding a particular mindset in regards to game design a little while after I started working on iPhone games, but I could never really articulate what I was feeling without sounding like a lazy game developer or religious nut. Danc’s article over at lostgarden reflects a lot of what I think about games as a medium, and what they can do, and where they are heading (good or bad). I’ve had this strange aversion to creating a gameplay ‘space’ where the amount of time spent playing a game almost directly correlates to the exact number of levels the game has.

Of course, any outsider looking in would probably see the flawed logic in that when you have the poster children of mobile games being heavily content driven. Danc argues that content heavy games aren’t the way to go and are inefficient game design. But just looking at the iPhone market, what he’s saying seems at odds with what is garnering consumer attention.  But then again, games like Angry Birds and Cut the Rope may simply be outliers. A glance at the top of the charts reveals Fruit Ninja, Bejeweled 2 (most likely due to Bejeweled 3’s release), and the ever present Doodle Jump. All of these games very light on ‘content’ and steeped deep in core mechanics. So maybe hope isn’t lost :).

The reason I was feeling a bit of concern is there seems to be an influx of games trying to replicate the Angry Birds formula. Tons of levels, quick to go through, and a simple mechanic to play with. This may be playing a dangerous game, especially if you’re an indie. An indie’s time is extremely limited, and getting on that ‘endless treadmill’ to churn out levels is definitely not something you want to find yourself in if you wish to move on from a game and pursue something new.

There is something to be said for content-driven games created by indies though. They can work, but the path is extremely long and grueling. And in the end, you’re creating an experience that borders more on a book, or movie, rather than a game. I loved Braid and Limbo to death as they were amazing experiences and I’m glad they exist. But in all honesty, it’ll be a very long time before I ever revisit either. Their memory is more like a movie in my mind, not a game. I recall scenes, imagery, atmosphere, and mood. Oddly, I barely recall the puzzles in either and the platforming mechanics are forgettable. The very things that differentiate them as games versus other mediums are the things I recall the least about them.

Despite thinking ‘static levels’ are bad, the market can and will reward a game that has a decently fun mechanic and just pumps out content for it, very much like a season on a TV show. So as an indie, the market won’t punish you for it. Although you may soon find you’re punishing yourself :). Another way to look at it is a meter of progress. Some players prefers games with discrete levels because it gives them a sense of progress and direction. High score games have little direction in their minds because the ‘end goal’ is to get #1 on the leaderboards, which in most cases is impossible so the game loses value and becomes more of a toy. It’s purely a mindset and expectation those players enter the game with and something a less ‘content’ driven game has to deal with.

Disposable Games

One of the lines in the article that hit home the hardest for me was:

“As a designer, I feel like I’m wasting my life when I create a disposable game.”

What’s interesting is that above thought is far less pronounced in my mind when I think about developing for say…The DS, Xbox 360, PC, Mac, etc. In the App Store there are literally thousands of games that can probably qualify as ‘disposable games’. I’ve played plenty of them, my friends have played plenty. And it’s not that they are bad games by any means, as we tend to get enjoyment out of them. It’s just that the amount of time we enjoy them is for but a fleeting second and then we move on. Gone are the months of hard work that designer/developer has put into that experience. Is it worth it? Why does this feel more relevant in the App Store? Is it because it’s harder to swallow that a $60 dollar game is disposable? Do those other platforms promote ‘deeper’ gameplay in general vs the more diverse App Store?

It’s not lost on me the context in which these games are played. Most are played a couple of minutes at a time, often times while the player is outside their home. So any long term investment needs to come from several play sessions over a very long time period as opposed to a more traditional game where investment usually comes in blocks of hours. Just because you’ll only have a few spare moments to entertain the player when they open the game doesn’t mean they also have to be the last. Words with Friends is an amazing example of this very concept, but I don’t think asynchronous play is the only answer to this, and beyond turn-based games isn’t a very good one.

Games like Angry Birds and Cut the Rope thrive on that concept by creating “tons” of static content that is consumable in very small time periods. Guess what? Once the player is done with all the levels, there’s little incentive to come back beyond the pure ‘fun’ of the mechanics. The question is, would players play the same puzzle again knowing the solution just for the sake of playing it? They seem to be in the content business now, which I guess isn’t a bad thing when business is good.

Some of the warmest comments I’ve received about Tilt to Live have been from players that begin their e-mails saying they’ve been playing this game since release. That’s 10 months and counting. If people are still playing it today, maybe we’ve created a game that isn’t disposable? I think Danc said it best about creating a deep game versus a content heavy game:

At a certain level of depth, a game transcends being a disposable blip and turns into a life-long hobby

That’s definitely a goal to keep in mind when I’m trying to create a meaningful game.

This post is more of a public service announcement. Prior to Tilt to Live’s Game Center/Retina update we wanted to extensively test the game with a wider tester base. So we ran a small ‘open beta’ (as open as Apple’s ad-hoc program would allow us). Prior to iOS 4.0 users had to do a cumbersome dance to get an ad-hoc game on their devices. And by cumbersome, I mean anything dealing with the desktop iTunes client. There was a lot of room for error, and for those (like me) that loathe syncing with iTunes, it creates a barrier because the act of adding an ad-hoc pretty much wipes my personal device since I buy all my apps 100% on the device and never sync.

Enter iOS 4.0. I discovered this tidbit on Twitter one day. Sadly, I can’t recall who tweeted or retweeted it, but thanks!

With the new iPhone iOS 4, you can distribute apps wirelessly without iTunes intervention. You still need to collect the appropriate devices id’s and create the appropriate provisioning profiles but if you already have those sending out files is easy.

The benefit? Oh where to start? Your testers no longer need to be tethered to a desktop to actually test your app! Our beta e-mails contains direct links to the provisioning and ipa file. The user simply has to tap on both and the game installs over the air! It’s almost easier than buying an app on the app store. The barrier to beta testing has been dramatically lowered because of just this one feature. You can almost coin it as ‘one-click beta installs’. It’s good stuff.

The other upshot? You get more feedback. Some beta testers may simply be out and about and won’t remember to connect to their iTunes client when they return home for the day. We had a lot more responses this go around and even some quick back and forth e-mail discussions as people installed, played, and replied all in one sitting.

Another good thing is we were able to get some ‘field data’ on our Game Center implementation. I would imagine most people have wifi on their homes nowadays. We were getting some feedback from some testers that were on EDGE or 3G that Game Center was causing a long ‘pause’ between games. This was something that didn’t turn up in our internal testing because we’re always on Wifi. Turning over to 3G to test still didn’t give me any hang ups. So just the knowledge that a good portion of people were getting a significantly slower response from GC prompted me to investigate better ways to mitigate this and ‘hide’ the response time delay so users weren’t met with an unresponsive UI.

Downsides? It’s a bit cumbersome to create a build for wireless distro as you’re required to do a ‘build and archive’ from XCode. I have an automated build process for the old-school ad-hoc way. I wish there was a way to automate this as well. I feel that there might be a way, but not sure if ‘build and archive’ is doing any magic behind the scenes. If anyone’s got any info on this or whether xcodebuild has some way of doing this all through the command line please let me know!

A quick guide to build a wireless distro game or app

1. Choose Build->Build and Archive

2. If it already isn’t open, open the Organizer window (window->Organizer) and choose ‘Archived Applications.

3. Highlight the build you just archived and click on “Share Application”

4. Select “Distribute for Enterprise”. The correct provisioning profile should be automatically selected. If not, correct it.

5. At this point you’re presented with a form (pictured below) that you need to fill out.

  • URL: You need to decide beforehand what the name of the ipa and the location on a webserver the file will reside at. For this example we’ll use ‘http://www.onemanleft.com/tilttotlive/Tilt_to_Live.ipa’
  • Title/Subtitle: self explanatory.
  • Large/Small image URL: not needed. But since I had this on hand I just put them in the same folder on the web server as the ipa file.

Now when you click ‘OK’ it will ask you to save the file. Be sure to save it as the same file name you gave it in the URL (in our previous example it was ‘Tilt_to_Live.ipa’).

Now upload both the ipa and plist file to the URL you put in the form. Drop the index.php file created by Jeffrey Sambells in this post to the directory you uploaded the IPA file and you’re good to go. This index file will generate the links for both the provisioning and ipa files.

Now any user that is in the provisioning profile can visit that link in safari on their device and download the app directly. Or more conveniently, you can just copy and those links into an e-mail :).

Ok, that title is kind of misleading. But for those who caught the reference, *high five*. I actually pulled gyroscope support from our latest Tilt to Live update. I had it implemented into the game at one point but through beta testing eventually killed the feature. I just wanted to go over the details as to why it went the way of the dodo bird.

Gyroscope != Accelerometer

Alright this a biggie. With the gyroscope on iPhone you can detect the orientation of the device in any position. This is great and actually not a limiting feature. You can calibrate the device in any position. Hell, you can calibrate the device while hanging upside from a jungle gym on a pre-school playground and it will work without a hitch. But there is a subtle difference as to how your tilt offset is calculated. The gyroscope offsets are calculated off of absolute orientations, where as using the accelerometer offsets are calculated off of relative orientations to a gravity vector.

Before I go any further, let me explain why I went down this dead path for tilt controls. When you calibrate a device off of the accelerometer there is a ‘gymbal lock’-esque problem when the device is 100% vertical. Any horizontal tilt cannot be detected because you’ve lost this degree of freedom since one of your tilt axis is aligned with gravity (what the accelerometer works off of). When the gyroscope was announced I naively thought, “Hey we can probably make the perfect tilt controls now that work in any position!” I got the ‘any position’ part down, but it was far from perfect.

Complexity in the UI

Another ding against gyroscope was due to the nature of how it worked, I couldn’t find a way to automatically turn it on and off without a large chance of the user becoming confused. As a result, I needed to create some UI interface to enable gyroscope controls. And wow, it was a hard one. Trying to explain the nuance of how the gyroscope works, without getting technical so that the user can make an informed decision as to whether they want it or not was…a bit weird. How weird? When you have to write up text that says this:

You’re probably doing it wrong.

We found it pretty funny and in line with the rest of the humor of Tilt to Live. But it just wasn’t easy to explain. Complexity in the UI was actually one of the main reasons we decided to pull it. We didn’t want Tilt to Live’s calibration to become this screen of knobs and switches, even when you’re doing a custom setting.

We weren’t kidding. Cars = bad

Step 1. Calibrate using gyroscope

Step 2. Play the game. (You so happen to be in a moving vehicle)

Step 3. This vehicle takes a right hand turn

Step 4. Owned.

The handset, in “real world” space is actually rotating when the car turns, but in local space relative to the car it isn’t. Bad news for people who are now wondering why their little arrow turned suicidal after they got off that exit ramp from the highway.

This issue ultimately clinched it. Having to calibrate not only the orientation but the actually direction a player is facing was too much. There was too large of a margin for error.

Gyroscope is awesome, we just weren’t meant to be….

With all that said, playing around with the gyroscope was awesome. It allowed me to play Tilt to Live in one-handed portrait mode because of the freedom it provided with calibration. But that freedom is very short-lived as soon as I get up, turn in my chair, or any other minor movement.

In the end, if you’re making a tilt-based game mechanic gyroscope may be of a more limited use when you actually stop and think about it. Unlike me, who did very little thinking and went ahead and tried it :). I did have a period in there where I was completely convinced that there was an elegant solution to combining the accelerometer data and the gyroscope data to create a fully working “hybrid” of sorts. It never came to me, but I’m sure someone out there much smarter than me that could write a proof proving or disproving this problem and make my head explode.

Lot’s going on in OML-Land. TTL HD is out the door. TTL HD 1.1 is already in Apple’s queue (fixing a horrible crash for our international users). TTL 1.5 (iPhone) is in testing right now. On top of some R&D type stuff I’m messing around with so we can transition to our next project more smoothly.

So retina graphics are all the rage at the moment. If you were lucky to develop your game assets all in a vector-based format, supporting retina graphics was a bit easier. Luckily for us, Tilt to Live was all done in Adobe Illustrator. With a few tweaks to how sprites are rendered on the iPhone I had retina working in an afternoon.

Now, retina is all dandy until you get back onto the iPad.  If you are using the [UIScreen mainscreen].scale method to detect retina, be weary for iPad users. Things get a bit tricky on the iPad because:

  1. If you’re using the @2x trick, this doesn’t work on the iPad. This caused a few problems because some of our asset metadata relies on this as well so it caused a few minor headaches.
  2. Users can toggle the x2 mode mid-game.

At first I thought I could code to allow the iPad to load the retina graphics for a spiffy looking Tilt to Live. But the realization of #2 stopped me from pursuing it. Plus, with Tilt to Live HD on the app store now with even better graphics there really wasn’t a need to do it.

So if you plan on allowing iPad users to load retina graphics, it doesn’t exactly come as easy as it is on the iPhone 4. You may pretty much have to treat it in a similar fashion as a screen resolution change on a PC. This sometimes involves unloading textures, putting a loadscreen up, etc.

Next week I may go over some of things I came across implementing tilt controls with a gyroscope, which wasn’t exactly straightforward…