Noel

Independent game designer and programmer. Created Subterfuge, Casey's Contraptions, Flower Garden. Runner. Cyclist. Nature enthusiast. Magic addict. @noel_llopis.

Handling App Store and LinkShare Links

One of the perks of being part of the App Treasures label is that we get some nice cross-promotion with an in-game view to display other titles in the label. This list is, of course, stored in our server and pulled in through a standard UIWebView. It links to other pages with details for each of our games, and a link to buy it directly from the App Store. Everything is really straightforward, except for the App Store link.

AppTreasuresWebView

By default, the UIWebView will try to open the App Store link itself, which results in an error. What we want to do instead is intercept the request and launch it directly with an NSURLConnection so the call can be redirected to the iPhone App Store app. The best place to implement this is in the -[UIWebViewDelegate webView:shouldStartLoadWithRequest:navigationType:] method:

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
    if ([[[request URL] host] isEqualToString:@"phobos.apple.com"])
    {
        NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[request URL]] delegate:self startImmediately:YES];
        [conn release];
        return NO;
    }
    return YES;
}

While we’re in the topic of links, I also recently added some LinkShare links to my apps. The 5% kickback for each purchase is nice, but the tracking capabilities it gives you is the real reason I wanted to use it. The way LinkShare works is by providing a custom URL that contains your referral ID to allow LinkShare to track the transaction. Unfortunately, unlike the Amazon referral program for example, LinkShare is a third party company and is not tied directly into the App Store. That means the links they provide go through click.linksynergy.com and then are redirected to the App Store. The result is that trying to follow one of those links from your app will result in Safari coming up, opening up a new page, shutting down, and then opening the App Store app. Not pretty!

Fortunately, there’s a workaround. Just like we did with the App Store links, we can open the LinkShare link directly with a NSURLConnection instead of letting Safari handle it. Then, once the link resolves to the forwarded one, we can open it directly with the App Store app:

- (IBAction)buyItNow
{
    NSString* link = @"http://click.linksynergy.com/fs-bin/click?........";
    NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:link]] delegate:self startImmediately:YES];
    [conn release];    
}

- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)response
{
    m_iTunesURL = [response URL];
    return request;
}

- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
    [[UIApplication sharedApplication] openURL:m_iTunesURL];
}

Voila! The user goes directly to the App Store page, there are no annoying Safari transitions, and you still get the referral bonus.

Incidentally, most of this is already documented in an Apple Technical Q&A note, but it’s kind of hidden away and I think most people don’t know about it.

If you’re using LinkShare, you should also check out this post at Mobile Orchard. One of the things I learned there was the use of the &u1 parameter, which allows you to tag links with arbitrary information so you can track where purchases came from. Knowing where people are buying your app from is extremely helpful to know how to maximize sales!

[Edit: Sam Steele pointed me to the source code for the Last.fm app which handles all the URL redirects. Thanks!]

Environment Mapping Demo With OpenGL ES 1.1

CarI just finished creating a graphics demo for a chapter I’m writing for the book iPhone Advanced Projects edited by Dave Mark. In the chapter I go over a few different lighting techniques and go in detail on how to do masked environment mapping on an iPhone 3G with OpenGL ES 1.1.

The demo ended up looking pretty good, so I decided to upload a quick video showing the different lighting modes:

  • Diffuse texture only
  • Diffuse texture plus ambient and diffuse lighting
  • Diffuse texture plus ambient, diffuse, and specular lighting (as usually, per-vertex lighting looks pretty bad, even though this is a relatively high-poly model)
  • Fully reflective environment map (using the normal environment map technique)
  • Environment map added to the diffuse texture and lighting
  • Environment map with a reflection mask plus diffuse texture and lighting (two passes on an iPhone 3G–or one pass if you’re not using the diffuse alpha channel)

The chapter in the book will go in detail into each of those techniques, building up to the last one. Full source code will be included as well.

Some of these techniques will also be covered in my upcoming Two Day iPhone OpenGL Class organized in collaboration with Mobile Orchard.

Targeting 2.x With 3.0 Features. Trouble Ahead.

iPhone-SDK-for-iPhone-OS-3-0-Beta-2-Released-Download-Here-2As far as Apple goes, OS 2.x doesn’t exist anymore. That much was clear from WWDC when we asked their engineers any questions about it. And as cool as 3.0 is, with all the new nifty features, the reality is that there’s still a good percentage of (mostly iPod Touch) users out there still on 2.2. We can have our cake and eat it too by targeting 2.x and still using a few select 3.0 features. But it’s more complicated than Apple made it out to be. Trouble is looming just under the surface.

Trouble With Versions

When you install the 3.0 SDK and create a new project, it will be automatically set up to build only for 3.0. To target earlier versions while still having access to 3.0 features, you need to take a few extra step. These steps are described in detail in the readme of the MailComposer sample (iPhone dev account required). My friend Serban also wrote about how to do it when you add Snow Leopard to the mix.

The required steps are:

  • Under project properties, set up the Base SDK setting to be OS 3.0

step1

  • Also in project properties, change the iPhone OS Deployment Target to OS 2.2 (or whichever version you want to target).

step2

  • Go to target properties, and add a 3.0 library with the features you need. Make sure you set its type to Weak instead of Required.

step4

  • In your code, check that a feature is available before using it. For example, you can do this check to see if the in-app mail functionality is available:
Class mailClass = (NSClassFromString(@"MFMailComposeViewController"));
 return (mailClass != nil && [mailClass canSendMail]);
  • Make sure you set your app to build with the 3.0 SDK and off you go.

step3

If all goes well, it should run under 2.x and 3.0. If all goes well…

Trouble With Libraries

If that was the end of the story, then we would all be happy and I wouldn’t have to write this entry. And for a while I really thought that was everything I had to do to get Flower Garden to use 3.0 features and still work on 2.x devices. Everything compiled fine, but when I went to run it on a 2.2 device, it crashed.

Looking at the crash logs, it was crashing inside a static library that used Objective C and UIKit. Digging further, it seemed that function calls were being sent to the wrong place. What was going on?

At this point I realized the root of this problem was the linker flags I was using. As soon as I started using the 3.0 SDK, I had to add the -all_load linker flag in order to be able to use the static library. I believe this loads all the symbols used by the libraries and links with them at link time. Without it, the library code would crash at runtime as soon as it was executed

The -all_load flag seems fine, except that the 2.x and 3.x versions of the SDK have different libraries and resolve symbols to different locations. So by doing -all_load, we’re linking against the location of the 3.0 version and trying to run it on 2.x. Bad idea.

I thought long and hard on how to get around this. I came up with all sorts of crazy schemes, and after a couple frustrating days, I gave up. Then, all of a sudden, I realized that it had an embarrassingly simple solution: Don’t use a library! I’m not kidding. Just move the files in XCode directly into your main game target and you’re done. No -all_load and everything works fine.

Yes, I’m still embarrassed for not figuring that out after 30 seconds…

Trouble With Compilers

So all happy with that discovery, I rebuild and run the app and… crash again!

The call stack this time looked like this:

Thread 0 Crashed:
0   dyld                              0x2fe01060 dyld_fatal_error + 0
1   dyld                              0x2fe07ca8 dyld::bindLazySymbol(mach_header const*, unsigned long*) + 484
2   dyld                              0x2fe15eb4 stub_binding_helper_interface + 12

What was going on in there? Some Googling and searching in the iPhone forum later, I learned that SDK 3.0 uses a different version of GCC (4.2 instead of 4.0). That means it will try to use some runtime functions that are not available with earlier versions. In particular, my crash was related to subtracting two uint64_t variables. Re-writing the code by casting the values to uint32_t before doing the operation fixed the problem. There’s an ugly “solution” for you!

So how do you know if something will work on 2.0? I don’t have a good answer for that other than test it as much as you can. Does someone have a better solution?

The good news is that, after I made those fixes, Flower Garden was happily running on 2.2 and 3.0. Now I can finally roll out in-app email without giving up on 2.x devices and cutting my potential customer base (or depriving current users of future updates).

Open Questions

Going through this answered a few questions, but also created a few new ones. Maybe someone here will know the answer or will be able to point me in the right direction.

  • Does anyone know how to debug your OS 3.0 app on the simulator set to 2.2? Whenever I launch it from the debugger, the simulator gets set to 3.0. Even if I set it to 2.2, I wonder if it will behave the same as a 2.2 device.
  • I’ve heard rumours about somehow, packing two versions of the app in the same executable (kind of like the universal MacOS executables with both a PowerPC and an Intel version). Has anyone done something like that with the iPhone? Any docs on that?

Balancing Flowers

I feel bad for the designers of games like Civilization or Supreme Commander. And I don’t even want to think about World of Warcraft. I thought it was tricky to balance the different flowers in Flower Garden, so I can only imagine the amount of time and effort than went into tweaking all the properties of the many dozens of units in those games to balance them just right.

At first, things sounded simple enough: Create 20 different seeds, with varied looks and properties. I had a really cool tool to tweak the flower DNA in real time (more on that another day), so how hard could it be?

The main properties I had to balance were amount of care required (as in, how often you had to water them before they would go dry) and how long the flower took to grow. The first few flowers came along just fine, but after the fifth or sixth seed, they all started blurring together. Did I have a fast-growing flower that needed a lot of care already? To get around this, I started writing all the seeds I had done so far and their characteristics in a text file so I could refer to them easily.

After a few more seeds, I knew I was in trouble again. Reading through all the flowers was a pain, but now I was starting to forget what they looked like. Did I already have an orange flower with a few, large petals? How about a small white one with lots of rounded petals and glossy leaves? The text file didn’t cut it anymore, I had to go graphical. So I created a document with a picture of each flower along with all its relevant information (name, growth time, and amount of care).

This helped a lot, but it eventually became inadequate when I started creating the unlock conditions and balancing and the different seeds in order of difficulty. I just wasn’t able to look at a list of 20 entries, each of them with 3 key elements (care, duration, and unlock condition) and keep it all in my head to make intelligent decisions based on it.

I’m a very visually-oriented person. Whenever I can, I try to solve problem visually instead of memorizing lists or plugging equations. In particular, I love to take a multi-dimensional problem and visualize it along its main axes. So I took the next logical step to help me make sense of all that data and created a seed chart.

FlowerSequence_s

This seed chart is a two-dimensional arrangement of all the common seeds in the game, along with their picture and the key information we had before (there are another dozen bonus seeds that aren’t listed in this chart). The horizontal axis indicates how much care a plant needs. Specifically, it shows how many segments in the water meter before it dries out (and each segment is 3 hours). The vertical axis indicates the growth duration for the plant in real time. Instead of making it a straight, linear scale, I decided to go with regions, which is how they are presented in the game (“Instant”, “A few hours”, “Overnight”, “A few days”, “About a week”, and “Quite a while!”). Within the region, they’re roughly ordered by duration (shorter towards the top, longer towards the bottom).

Now it was really easy to see at a glance the key characteristics for each seed, see where I had clusters, and where I had empty spaces that no seeds were currently using. As a bonus, I was able to come up with a rough ordering indicating the level of difficulty for each seed. The further down and to the right a seed was, the more difficult it was to grow.

That allowed me to block out some regions (dotted red lines) indicating difficulty ratings, which are listed in the game in the seed information as “Piece of cake”, “Easy”, “Moderate”, “Hard”, or “Experts only”. Notice how the lines separating the regions are not parallel (even though the vertical axis is kind of logarithmic). That’s because moving along the horizontal axis increases difficulty a lot faster than moving down the vertical axis. So even a relatively complex relationship like that can be observed at a glance from the chart.

Another great benefit of the seed chart is that I was able to draw paths between seeds, showing the unlocking relationships between them. Before it was hard to see these relationships in text, but now it was very visual, and I could make sure that easier flowers unlocked the path to harder ones as long as the unlock relationship flowed roughly from the top left to the bottom right.

As a side effect, the chart allowed me to learn even more things about the data than I had expected. For example, I was able to see which colors I had used so far, and which colors I still needed to use. One really interesting thing I noticed is that colors were clustering around specific areas. Red colors seemed to be mostly in the harder flowers. Yellow colors were predominant with the dry plants, and blue colors with the wetter ones. I thought that was pretty neat, so I tweaked a few seeds here and there to make that color connection even stronger.

The lesson learned here is that the old saying applies even more in this age of information: One picture is worth one mega of words.

Teaching a Two-Day OpenGL iPhone Class. Register Now!

openglI’m excited to announce the intensive, two-day class on OpenGL for the iPhone that I’ll be teaching. The class will be held September 26th-27th, in Denver, right before the 360iDev conference, and it’s part of the Mobile Orchard Workshops.

The class is aimed at iPhone developers without previous OpenGL experience. It’s going to be very hands-on, and you’ll create both 2D and 3D applications during the weekend. You’ll learn all the basics: cameras, transforms, and how to draw meshes, but we’ll also cover some more advanced topics such as lighting, multitexturing, point sprites, and even render targets. Most importantly, you’ll walk away with a solid understanding of the basis, which will allow you to continue learning OpenGL and advanced computer graphics on your own from the docs, samples, or even browsing the API directly.

The main requirement for the class is that you’re familiar with the iPhone development environment and that you have basic knowledge of the C language. Beyond that, to the the most out of the course, you should be familiar with the basics of linear algebra (vector, matrices, and dot products). Anything else, we’ll cover it all during the class.

Registration is now open, and you can get some great discounts by registering early and attending the 360iDev conference. For more details, check the official announcement page.

Hope to see some of you there!