Kick Ass for iOS (iPhone, iPod touch and iPad) has been out for a couple of weeks now. This post is intended to be an analysis of how the launch went, how the app has been doing and what steps are needed to improve it. I might break it into smaller pieces, but I want to be able to begin on Kick Ass 1.2 as soon as possible so it might just be one large wall of text.
The things I will discuss are the before, now and after. I’ll try to include as much imagery as possible and be as forthright as I can. Let’s begin shall we?
- Before
- Now (coming soon!)
- After (coming soon!)
Before
This section is about the development up until the launch. I will begin with some history, move on to some technical bits and top it off with a discussion about the launch.
History
The inspiration came from (surprisingly enough) the web version of Kick Ass, found at http://erkie.github.com/. The web version was immensely popular and was written about all over the web and rough estimations (and according to Google Analytics) say that it has had around 1 million unique visitors to date. It still has a steady stream of visitors.
A couple of people wrote to me requesting me to make it work for their iPhones. Seeing as it uses open web technologies such as the canvas element and pure JavaScript it should have beem possible. The ship came up on the screen when you pressed the button, so it did work, but because the iPhone doesn’t have a keyboard, steering was not possible. It seemed to be an easy fix to just add the screen controls.
Thus I encountered the first and largest roadblock of mobile application development. Mobile devices are sloooooooow. You could get a couple of frames per second but that’s not good user experience. The second is that from my simple tests, Mobile Safari did not take kindly to bookmarklets: Pressing and holding the javascript link opens up an actionsheet with limited options, no “Save link to bookmarks”.
So optimizing the existing script for mobile browsers was not an option. The second option was to make a dedicated app and put it up on the App Store. The advantages of going native was speed. Objective-C intermixed with C and C++ would definitely be a lot faster than in-browser JavaScript. I haven’t done any tests to prove this but I think it goes without saying. Other advantages would be faster drawing which I’m guessing is a huge bottleneck for the HTML-based version. Though I have seen some impressive apps using canvas for iOS, I don’t think that it would work for this particular situation. Another advantage was that I had just gotten an Apple Developer license for my birthday!
Selling in the App Store was another advantage. Apple makes it so easy to create an app and actually sell it without much hassle from the developer or the user. When Kick Ass went viral I was still in school and took the odd job when I could get one. Selling something that I had created and marketed myself was not even in the realm of possibility, let alone making a decent living off of it. It’s funny how life can turn things around in a matter of hours, right? With 1 million users (not active) there is definitely a possibility. 7 months later and I have finished school and am (un)officially unemployed (on a summer vacation). Making a living is now more important than ever.
Early stages of development
Prior to this app I had no knowledge of developing for iOS. I had touched upon the occasional Objective-C but never really understood how it all fit together. So I started reading the Apple Developer documentation which resulted in nothing of use. It consisted mostly of technical information and nothing on how making real-world applications. So I downloaded all of Stanford’s lectures on iTunes U. They were exactly what I needed, and after the four of fifth lecture I was ready to go!
It began slowly. Just trying to get to know the tools and such. This turned into trying to draw a ship over a small browser window. (This was quite tricky for a beginner!) After that getting the interaction with the browser to work (destruction of elements). This was fairly easy and took only a couple of weeks. The downside was performance. Trying to destroy a huge page was nearly impossible and locked up the entire app for several seconds at a time. So working on performance issues was the most time consuming task and is the reason it took 4 months to complete.
The UI was also a difficult part. Making intuitive and fluid UI’s is not as easy as it looks. Thanks to my bro the app looks fantastic, but the touch-and-feel-part is up to the programmer to do great. Johan’s whipping when it didn’t work too well helped a lot. I’m still not 100% happy with the UI. One part being the URL-bar. I would have wanted a navigationbar that follows the browser when scrolled like in Mobile Safari, but thanks to Apple’s restrictions this is not possible.
All the difficult and bad stuff apart, making apps for mobile devices is rewarding! There is something about holding your own creation in your bare hands that is quite a powerful experience. It takes it to a new personal level. I enjoyed it.
Performance tuning
You’d think that blowing stuff up is an easy thing, considering how easy it was in the browser. Now I even had a native language to do it in! It still turns out that it is slow.
It’s not the shooting that is slow and it is not the drawing (mostly). It is the redrawing of destroyed webpages. Say you hide/remove an element in your browser; it happens instantaneously. You start noticing a problem if you try to remove tens or hundreds of elements at the same time. For a mobile browser it is almost the same. But this rears its ugly head after you remove only one element on a large page, or two/three on a smaller webpage. You can try it out yourself. Go to reddit.com on your iOS device and pick a random comments-thread. Scroll down to the comments and press the +-sign next to the author of a comment to hide the thread. How long did it take before the thread disappeared? On my 1st gen iPod touch it takes around half a second. On an iPhone 4 it still takes a considerable amount of time, for a game, where you’d want 40-60 frames per second. Even if it just takes 0.1 seconds it averages out to 10 frames per second.
To circumvent these problems I changed the mechanics of the game a bit. Instead of removing the elements I simply hide them. This action is actually hardware accelerated so it’s lightning fast and it makes the game a bit more challenging to play (no more shooting at the exact same place the entire time).
The second large performance issue was the collision detection. In the first version of Kick Ass for web I maintained a list of element’s positions that were destroyable. For every frame I looped through that list and looked for a collision. When an element was removed I had to update that index, because elements moved up or changed dimensions due to losing a child element. This resulted in bad performance when removing elements, so I found a native DOM-method that did it for me. document.elementFromPoint(x, y) which was a lifesaver! Naturally I tried to incorporate it into the iOS-version too. The bad news was that, because I was running the game on a separate thread, I had to lock that thread every time I wanted to search for collisions. This could cause stuttering and really annoying waits.
Then on a vacation to Tenerife it hit me: As I was only hiding the elements now I could maintain a list of rectangles that would be the same for the remainder of the session! And because it was on a mobile device the sites were mostly static anyway. The problem with this was that updating the index could take up to 5 seconds, and completely locking up the main thread during (and there is no way to run web browsers on different threads, or separate the JavaScript execution to another thread, thanks Apple). That was a sacrifice I had to live with, seeing as the game was running at a steady 30 fps even during the destruction. So if it ever locks up for more than a second, it’s because the game is updating its enemy index. To force this you can shake your device, and this will also show which elements you have left.
Threaded drawing
As I mentioned before the game was on another thread, but not the execution of JavaScript (my bridge to the website). So when removing elements on large pages the JavaScript-code injected to do that could take tens of milliseconds or up to 50 milliseconds or more. This caused really annoying stuttering when drawing was done by CoreGraphics, which also was on the same thread. To be able to draw on the game thread I had to use OpenGL. However, overlaying an OpenGL view on top of another view and having the OpenGL view non-opaque is strongly discouraged by Apple. Big let down for the OpenGL-party. My tests show that over 30% of the total running time is compositing the to layers together. That is not good, and I don’t like it at all, but I haven’t found an easier way to do it. I have a thread running on Stackoverflow with bounty, but haven’t got anything valuable out of it.
The launch
The most difficult part about making something is getting to point where you are content with it. Launching a product that you’re not 100% happy with is not good for the mind or for the users. Finding bugs in the last minute can be even worse; if you find one, how do you know that it was the last one? There could be a couple left creeping around somewhere. This was definitely the case with Kick Ass. One day I was prepared for launch, but the next I had found several critical bugs. When I finally decided to launch, Apples uploading process was so difficult that I was afraid I broke something on the way. It hadn’t, and a week later it was on the App store! (Buuuut it had a critical bug that I had to fix before publicly announcing the launch).
Conclusion
So this was a brief outline of the performance woes I’ve had when making the app. I’m still looking to improve the app, so any ideas from you guys would be awesome. In the next post I will talk about the Now, how sales are going and what I could and should have done better ad my thoughts about the subject. After that I will talk about the future of Kick Ass the app and discuss what I will be improving and why.
Stay tuned!