Warcraft Characters: v1.0

Warcraft Characters: v1.0

Warcraft Characters was my first iPhone project, which let users see their character stats on the iPhone. This post focuses on how the first version came to be.

Why Characters?

Portraits were fetched and cached from Armory website. List of characters was also loaded from local cache - no network connection needed once saved.

Portraits were fetched and cached from Armory website. List of characters was also loaded from local cache - no network connection needed once saved.

The short version is that I wanted to:

  • learn something new
  • make something I’d use
  • enjoy doing it

… and I had:

  • a shiny iPhone
  • zero experience with compiled languages
  • a Loremaster-aspiring druid healer (before being a Loremaster was possible)

A Warcraft-related app was initially a suggestion of a friend of mine. I wasn’t too thrilled with the idea at first since I wanted to make something unique, and not piggyback on someone else’s creation. I warmed up to the idea eventually: It seemed simple enough for a first app, and I thought I’d get the opportunity to tackle quite a few things such as visual design, file storage and web requests to name a few… and nothing like it was on the app store. At this point, I didn’t even consider app store publishing. Besides, I always loved well-done character sheets on pen-and-paper RPGs, and this would give me a chance to do something similar on the iPhone. What was not to like? And off I went…

Firstborn iPhone app

Health and mana bar were pregenerated images made with Photoshop, the rest are Cocoa (native iPhone) objects.

Health and mana bar were pregenerated images made with Photoshop, the rest are Cocoa (native iPhone) objects.

Warcraft Characters was my first foray into Objective-C/Cocoa coding for the iPhone. My background is in Javascript (web dev, people), so the learning curve was steep – I was mostly banging my head against the wall for weeks almost every night. Bright side of this: I didn’t have to deal with Internet Explorer antiques.

Thankfully, I clicked with the Cocoa and Objective-C – most of my moments were ‘oooh, this makes so much sense!’ and ‘sweeeet!’, and after a month, I had my very first Cocoa object displayed on the screen. Note: iPhone dev kit includes Interface Builder, but as a perfectionist I prefered to add objects manually by code. This paid off later, too.

The App itself was a simple combination of Cocoa objects (table view, labels, background images), which fetched armory data and saved it locally. ‘Saved it locally’ was one of key points: I wanted character sheets to be viewable anywhere regardless of network connection.

Design, if you can call it that

Background image was predrawn in Photoshop, and region picker was hastly added after users requested it. This part of the app was least polished.

Background image was predrawn in Photoshop, and region picker was hastly added after users requested it. This part of the app was least polished.

I wasn’t fond of Characters’ look in the first version, but then again, I rarely like what I did a few versions ago…

Here was my design process:

  • draw mockup in Photoshop
  • place single image app on the iPhone
  • pretend the image is actual running Characters
  • repeat until ‘yea, this is it!’ feeling appears

Images, such as health and mana bars, were pre-generated in Photoshop. A more proper approach would be to generate gradient images programmatically and just apply color, but I didn’t get into CoreGraphics until the second version. The Photoshop solution was less elegant, but *much* faster.

Portrait images were fetched and saved directly from the armory server. It’s easy to figure out address for each once I got the naming pattern: gender id plus race id plus class id. So, male (id 0) tauren (id 6) druid (id 11) has image file named 0-6-11.gif. Since this character is level 80, file name is prefixed with /wow-80/ path.

Biggest hurdle

The most painful and almost deal-breaker issue? Getting character data off the Armory. Here’s a snippet of XML data when viewed with web browser:

<defenses>
<armor base="4877" effective="4877" percent="24.25" petBonus="-1"/>
<defense decreasePercent="0.00" increasePercent="0.00" plusDefense="0" rating="0" value="400.00"/>
<dodge increasePercent="0.00" percent="19.48" rating="0"/>
<parry increasePercent="0.00" percent="0.00" rating="0"/>
<block increasePercent="0.00" percent="0.00" rating="0"/>
<resilience damagePercent="0.00" hitPercent="0.00" value="0.00"/>
</defenses>
</pre>

Perfect, right? Even humans can read this! However, downloading this same exact URL with the iPhone resulted in this:

<li class="staticTip" onmouseover="javascript: setTipText("<span class='tooltipTitle'>Defense 400</span><span class = 'tooltipContentSpecial'>Defense Rating 0 (+0 Defense)</span><span class = 'tooltipContentSpecial'>Increases chance to Dodge, Block and Parry by 0%</span><span class = 'tooltipContentSpecial'>Decreases chance to be hit and critically hit by 0%<br/><span class = 'myGray'>(Before diminishing returns)</span></span>");">events={ mouseover=Object mouseout=Object }handle=function()
<span>Defense: </span>
<i>400</i>
</li>

That was bad. I wanted clean readable data, not the garbled final page in HTML format! Why was XSLT tranformation applied already? Wasn’t iPhone just supposed to download raw data I saw in the browser?

A few weeks and 1,000 unsuccessful attempts to figure out the issue, I found the solution in this line of code:

// fake that iPhone is Firefox browser to get XML file from the armory
[request setValue:@"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9) Gecko/2008061004 Firefox/3.0" forHTTPHeaderField: @"User-Agent"];

You see, if the Armory server thinks you’re a Firefox browser, it will send you data as XML, which is what I needed. Faking that my calls were sent from Firefox saved the day.

Cleared for launch

Old icon in v1.Tried to get

Old icon in v1. I spent most of the time trying to get W in with no success.

Icon for next version. Looks much better when I went with the flow rather than forcing W in it.

Icon for next version. Looks much better when I went with the flow rather than forcing W in it.

With the above combination of head-banging and ‘aha’ moments, as well as a dash of Photoshop, Characters v1.0 was born.

When the app worked well enough, it was natural to post it on the App Store. I didn’t have high expectations for it – while I was thrilled to get something out that worked, it wasn’t nearly as good as I wanted it, and on top of that, I was wary of copyright issues that might reject Characters from the start. Still, I did it for two reasons: test the waters, and ship something that works. As a perfectionist, I could work on an app forever, so I started the project determined to actually have a finished version I could possibly improve on later. That’s well summarized in this quote: “Real artists ship”.

After waiting about two weeks for Apple to clear Characters for the app store, I woke up to find 40 emails in my inbox from people who downloaded the app; mostly about asking for Characters to support EU servers. I can’t describe how exhilarated I was to get feedback from users!

For those of you working on your first apps and are unsure of yourselves, let me tell you that the learning experience and feeling of having your creation live is well worth the time and effort. You’ll have nights of frustration thinking ‘this #@!& just isn’t working!’, and that’s fine – persist through it, and results will show.

I rushed off to make an update that supported all international servers, and submitted it a few days later.

Extra credit for devs: Cocoa goodness

Since Characters was my first contact with Obj-C/Cocoa, you won’t find any secret Cocoa tips, but what first coding for iPhone did for this web developer:

  • great introduction to designs and patterns: With interpreted and loosely-typed Javascript, you can do things the right way or the wrong way, and it will usually work. Cocoa framework, on the other hand, almost forces you to follow certain patterns. For example, if you used UITableController object, you have used Model-View-Controller pattern. I could read about MVC forever, but actually using it is what made the light-bulb go on for me. This drastically affected how I wrote my future Javascript code in a positive way.
  • different ways to organize data: dictionaries, sets, arrays, Core Data. This was a good stepping stone from lenient Javascript to less forgiving C. I didn’t actually start to tackle pure C on this project, but Cocoa was a good crutch as I transitioned into it.
  • in the first version of Characters, my subclassing skills were less than ideal, and AppDelegate was overwhelmed with methods. I did better in the next version *grin*.
  • I simply love Cocoa method naming convention – it’s easy to read and is self-explanatory. Here’s what methods are called once Characters was initialized:
    [self setupApplicationDataWhenLaunched];
    [self updateCharacterListFromSavedXMLFiles];
    [self setupApplicationUIWhenLaunched];
    

    Quite readable, isn’t it?

  • Writing my own FileDownloader class was fun since url request API on iPhone didn’t support file downloads. It was my very first singleton class, too! I did away with singletons later, but it was fun experiment to make one.

That’s all folks! Feel free to contact me if there’s anything else you’d like to read. More about Characters v2 in next installment…

Leave a Reply