Tuesday, March 30, 2010

Those Pesky Crashes

Unless you have a dedicated team of testers working with you, it’s pretty easy to publish an app with bugs in it. Hopefully, the majority of your scenarios work because you’ve tried them out (that is assuming, of course, that you are not publishing titles for a device you’ve never seen - hello, iPad!). However, there is always some weird combination of user input you haven’t thought of that, apparently, everyone else has.

We’ve all been there - you write an app and a friend of yours wants to take a look. You reluctantly give up possession of your precious little baby and cringe in the background as your friend taps on all the wrong places. Three seconds later, he returns the device to you with your app all locked up or, better yet, not running at all. You and your friend never talk again.

Okay, so maybe that’s just me. However, my point is that even in these scenarios, you are pretty safe. Apart from losing a friendship or two, you can go home, try to recreate some of the issues, and fix the bugs you find along the way.

When you ship, however, chasing crashes becomes much more difficult. Apart from getting the occasional “The app crashes and it sucks! Don’t buy it” review, you don’t get much information about how your app performs. You may not even know that it crashes at all; not unless you look at Apple’s iTunes Connect portal in a little more detail.

I’ve just submitted an update for Doodle Blast! today and discovered this handy little button hiding underneath the application details:

Clicking on it, you get a nice little summary of what, if any, crashed have been reported:

Besides being told about the crashes, you can download a .crash file, which magically opens up on your machine and shows you the full stack trace of your app at the time of the crash.

That’s pretty cool! I’ve worked on a variety of platforms where you might get some core dumps but, no matter how hard you try, you can never get your hands on the actual stack trace. Either your symbols are too old, or they are from the wrong build, or you just didn’t clap your hands three times before throwing some salt over your shoulder. Whatever the case, the bottom line is that getting some useful information out of a crash log is always a challenge.

This is not the case here. You just need to know that these crash logs are available. I didn’t… until now. And, sadly, it turns out that Doodle Blast! crashes every now and then. Curious, I looked at the downloaded .crash log and discovered that if you tap on the Doodle Blast! title text in the main menu, bad things happen. Don’t do it, kids. You’ve been warned. Fix coming up in the next update…

Friday, March 26, 2010

Bigger Is Better

What a week! I always thought about porting Doodle Blast! onto the iPad at some point. But when Apple announced last Saturday that the iPad app submission deadline is on March 27th at 5pm, I realized that “at some point” has suddenly come to mean “now”.

I woke up on Sunday morning and started. I must admit, I felt a little overwhelmed. I haven’t even installed the required SDK yet, let alone read through the iPad documentation or try out the iPad Simulator. I like working on my own pace and suddenly having a hard deadline in a week felt strangely reminiscent of work.

I glanced through the docs and I ran into a very interesting point – in order to install the SDK you need to be running Snow Leopard. I was only running Leopard at the time. Hmm… Inquiring further into matter, I came to find a number of people complaining about Snow Leopard on the Internet about missing drivers and compatibility issues. Double hmm…

So I went down to the Apple store, picked up a copy of Snow Leopard, asked the sales girl whether I can boot up an Apple machine from an external hard drive, witnessed her nodding aggressively (although I had some doubts as to whether she had any clue about what I was asking), picked up an external HD and went home. Kudos to Apple, you actually can install and run an OS from an external hard drive pretty easily. The machine even shows you pretty chooser at startup time. If you are interested in doing the same, these instructions proved very useful. As a side note, though, Snow Leopard runs pretty smoothly. I was worried about having all my game-making tools work nicely with it, but they do, so my fear was unfounded.

Anyway, that killed my Sunday – lots of downloading, lots of shopping, lots of installing, and lots of reading.

What followed for the next five days was a whirlwind of coding and testing and rewriting and redrawing, an effort that eventually culminated in my iPad app submission about two hours ago, followed by a frantic re-submission about an hour later when I realized that my new code had a deadlock in it which didn’t show up in the simulator.

I’ll post some more highlights and gotcha’s in the coming days, but for now I’m getting sloshed on wine and hoping that I didn’t miss anything major (which is always possible, given that, like most mortals, I’ve never held the device in my hands). Good luck to me!

Tuesday, March 23, 2010

One Hot Doodle

The week is over (at least according to some strange iTunes clock) and Doodle Blast! is now officially out of the "New and Noteworthy" spotlight. There go the fictional millions ... *sigh*

But what's cool is that Doodle Blast! was just featured by Apple in their "What's Hot" list as well as the "Best Doodle Games" list. I wish I knew what either of these accolades actually mean, but, hey, I dig 'em! Thank you, man behind the curtain!

Saturday, March 20, 2010

Doodle Blast! score count passes 3000

Perhaps an insignificant milestone for some - yes, you, abitofcode and zombie - but Doodle Blast! has passed the "3, 000 unique scores" mark as of 5 minutes ago. Only 997, 000 more to go!

Thursday, March 18, 2010

Help Doodle Blast! hit Top 50!

You've read the story, you've played the game, you might as well admit it... you LOVE Doodle Blast! Now is your chance to get involved - help the game break into the top 50!

Doodle Blast! broke through the Top 75 games in the US store today. Given that this project started only as a weeklong last hurray for my recent dabbles with the iPhone, I'm very excited and very happy to see the game enjoy this unexpected success, however temporary it may be.

Despite the current spot light, the game is actually not generating too much money. You'd think that Top 100 is the final frontier. But, alas, no. It would be nice if the game sales managed to cover at least a portion of my hardware startup costs (I used to be a Windows junkie... I know...), but I'm not holding my breath.

Regardless, it would be a hoot to see the game make it to the top 100. Since you are reading this blog, you probably already know that Doodle Blast! is a completely indie production, with no studio backing, no advertising budget (or any budget for that matter), and, most of the time, no prior experience in working with any of the components that made Doodle Blast! into what it is (writing code on the Apple platform, creating trailers, sampling music and sound effects, ... sheesh!) How cool would it be if Doodle Blast! actually made it?

So, here is your chance to help - tell your friends, publish blogs, post tweets, and pass the word - Doodle Blast! is hella cool!

Wednesday, March 17, 2010

"New and Noteworthy" in the US Store

Alright, alright, I promise this is the last gloat (for today). Thanks for all the support!

Top 100, here we go!

Pictures are supposed to be worth a thousand words. This one is worth at least 99. Just snapped today in the US store!

Monday, March 15, 2010

Going International

Call me slow, but I just discovered that you can change the default store displayed in iTunes by clicking on the little flag icon in the corner. Who knew? So, for the first time ever, I was able to check out some of the feedback about Doodle Blast! posted by people from all over the world. For example, here is what people in the UK are saying:

"Remember drawing spaceships as a kid and then filling every available bit of their surface areas with guns? This is the tank equivalent! Photos and videos do not do this game justice. You have to play it and control the awesome firepower to really appreciate it."

"I'll take a gamble and say that this game's going to be as big as Doodle Jump and Angry Birds!"

"Cool style, not as good as doodle jump but well worth getting for a mess about"

"Omg this is the next Doodle Jump."

"...Not going to be the next Doodle Jump..."

"This is better and more addicting than Doodle Jump and Angry Birds"

First of all, thank you all for your support! It's cool to hear that UK is having some fun blasting out doodles. However, I also must say that I'm noticing an interesting debate going on. It seems that the question keeping the bulk of British population awake these nights is: Will Doodle Blast! be the next Doodle Jump?

Certainly, it's a topic worthy of a debate. Got an opinion? Let me know!

Oh, and here is a big shout out to Yasar from Turkey! He seems to be a Doodle Blast! fan as well - keep plowing through those meters, Yasar!

Friday, March 12, 2010

Skynet – How to Make The Player Fall While Having Fun Doing It

SPOILER ALERT: If you are a player of Doodle Blast!, this post will spoil some of the fun and mystique behind the game. Consider yourself warned.

One of the unexpected challenges I ran into with Doodle Blast! was difficulty. Some people picked up the game only to feel overwhelmed and lost within a few seconds. Others got bored in just about the same amount of time. Seeing these reactions, I began to wonder how I could dynamically adjust the game to adapt to the player’s abilities. If you are like me and enjoy having nice, slow starts, I wanted the game to take its time building up. If, on the other hand, you are like my brother, I wanted the game to hit you with everything it’s got as soon as possible. End result – we would both be happy because the game provided a different experience for the each of us. But how the heck do you solve this problem?

As it turns out, the solution I coded came in three parts:

  1. Variable aggressiveness – I could tell each enemy how aggressive I wanted it to be
  2. Feedback mechanism – Each enemy could report back on how effective it was at destroying the player
  3. “Skynet” – Central logic interpreted the feedback to adjust the aggressiveness of the next wave of enemies

Because I’m a geek and because it seemed right, the first two values were passed around as floats, ranging from 0 to 1. Zero in aggressiveness meant that the enemy was as passive as possible (it wouldn’t shoot, for example). Zero in feedback meant that the enemy was completely useless (it was killed before it even entered the screen). Ones indicated the opposite for both.

Since each type of enemy was its own class, each could also provide its own way of determining its effectiveness at being a killing machine. What I, then, did as a player was try playing against each of the enemies at various “aggressive” values to find a happy medium between being bored and not being able to keep up. This value (which for most enemies hovered around 0.65) was the golden standard that each enemy was trying to achieve. If it fell short, Skynet would yank up the aggressiveness of the next wave proportionately. If it overshot, Skynet would make the next wave less aggressive.

That was the basic idea. However, there are a couple of other tidbits worth mentioning.

Assaults – each wave of enemies of a similar type constituted an “assault”. If you were kicking butt across all assaults, Skynet would begin sending two or more assaults at a time to give you some extra excitement. If that proved to be too difficult, the concurrent assaults scaled back down.

Fire power – the relative aggressiveness of all enemies also adjusted based on the number of guns you carried. Basically, the more guns you had, the more indestructible you became and the more aggressive the enemies turned.

Shooting strategy – it doesn’t matter if you lose guns from your tank. The only thing that matters are the hit points of the tank itself. Hence, a particularly useful way to defeat the system was to continuously shoot only at the bottom right corner, and just pick up new guns when the old ones got destroyed. So much for Skynet. To counteract this strategy, I added "assassins". The game actually takes note of your favorite shooting spots and monitors the “histogram” it produces. Initially, it lets you get by. However, after the first 1000m, it sends a way of deadly assassins after you that target your tank directly without mercy. These assassins get spawned at the histogram minimum - meaning, at the place where you are least likely to shoot.

The end result of all this magic is that if I play poorly, I can get to about 600m. If I play really well, I can get to about 700m. And that was basically the aim – to give players an opportunity to enjoy bulk of the game play regardless of whether they were pros or rookies. But, as always, there is lots of room for error. Take “Nino", for example, topping the leader boards with a whooping 8561m under the belt. Kids these days…

Tuesday, March 9, 2010

Reaching Out to Younger Audiences

Hey Kids!
If you are digging the AWESOMENESSNESS of Doodle Blast! you are not alone! Check out this young lady kicking some serious butt...

Thanks to sowbug for sharing it!

Saturday, March 6, 2010

Doodle Blast! - Day 7 - Sweet Rest

I was done! So, on the seventh day I went to see a movie instead of sitting in front of a computer. There were a couple of pieces still missing, but all the functionality of Doodle Blast was there:
  1. Tank
  2. Stacking guns
  3. Projectiles
  4. Falling bonuses
  5. Static buildings, flickable soldiers, flying aircrafts
  6. Score counting
  7. Score tick marks
  8. Hit points, damage, and collisions
  9. Single and multi-touch support
  10. Sounds
  11. Menus
  12. Local scores
  13. Global scores
  14. Twitter integration
  15. Loading screen
What was missing was the final images (it’s hard to code and draw at the same time), a few more guns using the existing gun infrastructure (gun images along with data specifying firing frequency, aim speed, cool period, etc.), a few more enemies using the existing enemy infrastructure (images along with data specifying spawn frequency, hit points, damage, etc.), a few more buildings, and some sound tweaks.

After I took day 7 off, I spent three more days working on the above items. Yes, I know, I was cheating again.

However, I did a couple of changes that might interest you:
  1. I added logic to adjust sound volume based on game progression and the amount of mayhem on the screen.
  2. In an attempt to make the game playable by rookies as well as advanced destructionists, I added logic to monitor the user and adjust the difficulty level accordingly.
If either of these interests you, let me know and I will dig into more details with further posts. If not, there you have it folks – The Making of Doodle Blast! in a nutshell.

The final game stats were as follows:
78 code files, 7693 lines of code, 9 textures, 42 sounds, and, as of today, 1773 submitted online scores.

Friday, March 5, 2010

Doodle Blast! - Day 6 - Global Scores

Stats: 66 code files, 5811 lines of code, 6 textures, 247 world flags, 21 sounds

Today, I mostly played with global scores. iPhone has a very sexy control called UITableView. It is essentially a scrollable table of items with lots of possibilities for customization, supporting both linear and hierarchical data visualization. The trouble is that if you want to use all this goodness, you need to learn it first and that takes time. Fortunately for me, Apple has some pretty good documentation about it along with some fun sample code. Plus I found some even more interesting tutorial online. Good thing we have the internet!

Then I had to make sure that the table of scores showed up in Cocos2D mixed in with all the OpenGL goodness. Once again, I was in luck – lots of samples and, actually, a very clean way of doing it:
_tableController = [[ScoreTableController alloc] initWithStyle:UITableViewStylePlain];
UITableView* table = _tableController.tableView;
[[[CCDirector sharedDirector] openGLView] addSubview:table];
I wrote a custom ScoreTableController that subclasses UITableViewController and deals with all the custom display logic. Then I simply added the table that the controller manages as a sub-view of the root OpenGL view. I love it when frameworks actually make your life easier.

The one glitch I ran into was fading. The page that hosted the table view fades in and out of black when it first appears as well as when the user navigates back to the main menu. Cocos2D has a nice set of transitions built into it. However, the table wasn’t part of the OpenGL world and, hence, it was completely independent as far as fading was concerned. So what I ended up doing was fading in the table after the background was already fully there and, vice-versa, fading out the table before fading out the rest of the background. If you look for it in the final product, you can see it, but most people don’t notice.

Doodle Blast! - Day 5 - Menus and Scores

Stats: 60 code files, 5323 lines of code, 3 textures, 21 sounds

I’ve been checking to see how many views there are of each of the videos I post here and here is an interesting statistic:
Day 1 – prototype: 74 views
Day 2 – collisions: 105 views
Day 4 – flicks: 11 views
What’s up kids? Wanna know more about collisions or is it just the teenagers out there searching for YouTube videos that contain explosions and crashes? Flicks, on the other hand, not very popular. And here I thought that that post would be a hit. Oh well, I hope you are ready for some serious excitement, because on Day 5 I tackled the menu system!

Okay, okay, so maybe the menus are not that exciting, but they are still very important and based on some feedback, I still didn’t get it quite right. There were two big complaints. One, the game generates a random name for you to use for score keeping (picking one randomly out of a hat of about ten). That’s all nice, but it turns out that most people post their first global score without realizing that they need to change their name first, otherwise they will just end up posting their score with this generic name. And two, some people score a particular score they are proud of, but they happen to be out of WiFi / cell-phone range when that happens and can’t submit their victorious number at the time. Since there is no “post your high score later” feature, they forever lose the ability to gloat about their achievement in public leader boards. I’ll try to address both of these in the next update.

BTW, in case you were interested, all the scores are kept using the CocosLive service, which is a really nice addition to the Cocos2D library. Also, Doodle Blast is using the free Twitter access libraries published by Matt Gemmell. Thanks Matt!

Besides menus, I’ve added an About page for those 3 seconds of fame, tweaked how multi-touch fire works, and baked score markers into the game itself for extra motivation. The game currently only displays top 100 global scores as little ticks that scroll by in the background (along with top 100 local scores). However, the more people play the game and post their scores, the more out of reach these top 100 scores are getting. For example, Nino and Robin B scored 8561 and 5130 respectively. I don’t know how these guys did it, but I’m seriously impressed. My personal best is about 950. However, the point is that fewer and fewer people actually see score markers in the game any more. So, for the next update, I’m thinking of showing the top 100 scores along with the bottom 100 scores, just to give people who are still trying some hope.

And one more thing – updated gun behavior. Test players suggested to me that if you have guns that fire continuously and if you pick up a new gun by tapping on the falling bonus crate, that new gun should automatically join the continuous fire effort as soon as it’s able, without the user having to lift their fingers of the screen to engage it. Among the changes I’ve made today, I implemented that behavior. Also, I’ve added logic to monitor how many fingers are continuously pressed against the screen. When that number changes, I scan through all the guns that can fire continuously and redirect them such that each continuous touch gets its fair share of continuous gun fire, without the user having to do anything besides worry about catching all enemies. Try it out next time you play the game (but beware that not all guns fire continuously).

Wednesday, March 3, 2010

Doodle Blast! - Day 4 - Tweaks and More Flicks

Stats: 52 code files, 4588 lines of code, 2 textures, 20 sounds

Today was mostly about code clean up, bug hunting, and game play tweaks. The gist of the game was more-or-less there, but it wasn’t very playable yet and I wanted to spend some time tweaking details to make the game cuter. I was also starting to get a little tired and I needed to ease off just a touch.

One of the things I played with was flicking from the day before. You could flick the little soldiers into the air, but they looked very boring when they were falling down because I just applied a random rotation to them when they were released. So, I nixed that behavior and instead let them turn to follow the direction of their path, so that when they were falling down, they would do so head-first. And who doesn’t get a kick from seeing little stick figures falling head-first towards the ground???

I used the following method to turn a given sprite in the direction of the moving, underlying cpBody object:
cpVect direction = cpvnormalize(body->v);
float theta = -CC_RADIANS_TO_DEGREES(acosf(direction.x) * (direction.y > 0 ? 1.0f : -1.0f));
float currentAngle = sprite.rotation;
float dTheta = theta - currentAngle;
while (dTheta > 180) dTheta -= 360;
while (dTheta < -180) dTheta += 360;
Basically, the rotation of the sprite was attempting to conform to the velocity vector, but it did so over time with some easing-in baked in. The constants, in this case, were set to: DIRECTIONAL_MAX_THETA_DELTA = 5 (degrees) and DIRECTIONAL_MOVE_FACTOR = 0.3 (ie. 30%).

You will also notice that there are two types of runners here – the red ones, aka the suicide bombers, which don’t shoot but explode on contact and take away hit points, and the black ones that do shoot but don’t take any hit points when they crash into the tank (incidentally, I stole these pictures from Pop Fizz; that was before the final images were ready). The red peeps also had a count-down over them. Basically, they exploded when the count reached zero. In the final game, I cut that feature because it just polluted the UI and it didn’t really add that much more excitement to the game.

Doodle Blast! - Day 3 - Flicks

Stats: 52 code files, 4436 lines of code, 2 textures, 20 sounds

Today I introduced visual damage model on the player. Interestingly enough, most people playing Doodle Blast! for the first time completely miss it. I wanted to avoid having a health-meter bar or a number somewhere on the top of the screen, so I tried to solve this problem visually instead:

But as I said, most people miss it, so I might need to add a health bar after all.

The other big change in today’s build was the addition of flicking. Following the initial sketch of the game, I wanted to have little soldiers running around. I also wanted them to be flickable as flicking seems to be a popular gesture these days. The implementation was pretty simple.

Each soldier had a state variable, which could contain one of the following values:

  • ATTACKING – the soldier is all gong-ho in trying to get the player
  • GRABBED – the soldier is “grabbed” by a touch and is now following that touch around the screen
  • FALLING – the touch that “grabbed” a soldier ended, and the soldier is now falling
  • RECOVERING – the soldier hit the ground, but under some magic threshold speed. A timer has been set, after which the soldier will resume its attack.

To calculate how and whether a soldier was flicked after it was grabbed, I kept track of the movement of each touch. When I received a TouchMoved event, I used the last touch position along with the last touch time-stamp to compute the speed thusly:

touchSpeed = (currentLocation – lastLocation) / touchTimeDelta;

When the touch ended, I used the touchSpeed, clamped by some max value, and simply set the released soldier off in that direction.

This approach, however, created a problem. You suddenly couldn’t just shoot a soldier, because every touch near a soldier’s vicinity turned into a flick gesture. To solve this problem, I defined two constants: FLICK_TIME_EPSYLON and FLICK_DISTANCE_EPSYLON. If a given touch event took less time than FLICK_TIME_EPSYLON (0.3 secs) and if that touch event moved a total of less than FLICK_DISTANCE_EPSYLON (20 pixels), I wouldn’t consider that gesture a flick, but I would consider it a tap instead and still direct one of the guns to shoot at that location.

Finally, there was one more interesting change that I introduced the day before but didn’t get a chance to talk about yet. I wanted the tank and the stack of guns to feel like they are barely holding together as they clank along moving forward on a bumpy road. What I ended up doing was giving a random small impulse to the tank and to a random gun in the stack every 0 – 2 secs. You can see those bumps in the video from yesterday.

Monday, March 1, 2010

Doodle Blast! - Day 2 - Collisions

Stats: 50 code files, 3871 lines of code, 2 textures, 11 sounds

Today, I introduced a simple set of “enemies”. I added a helicopter I copied from the original game sketch and I also added a building that I shamelessly stole from Pop Fizz, the Airplanes world. I introduced the concept of enemy hit points, simple collision detection, and continuous fire. The final game supports continuous fire for only a certain types of guns to make the game play more varied and to prevent players from just holding their fingers at the corners of the screen as they plow forward. However, at this stage, I made every gun (namely the two that I implemented) support continuous fire. This was partly because it was fun to feel the destructive power of the tank and partly to run a preliminary test to see how many objects I could throw on the screen before the frame rate began to suffer. So far, the code faired remarkably well. Even in the craziest of situations, Cocos2D was pulling at a solid 45 fps.

The frequency at which the enemies were spawning was controlled by a constant and it was the first time I started playing with how many enemies are fun to destroy vs. how many enemies are just too overwhelming. I showed the preliminary results to my brother, pointed him to the constant and let him play. His findings were that there was no such thing as too many enemies and he was rooting for the biggest mayhem on the screen he could get. I liked the idea of having a more leisurely play. To accommodate us both as players, I’ve started scheming for an enemy-spawning logic that adapts to the player’s style, lovingly referring to it as Skynet. But I’m getting ahead of myself because Skynet didn’t get to see the light of day until a couple of days later.

The most interesting part in today’s addition was the collision detection elimination. As I mentioned before, Chipmunk has a handy way of filtering out unnecessary collisions, thus decreasing the amount of computation and boosting perf. There are three tiers at which you can filter out collisions
  • Groups
  • Layers
  • Collision handlers
You can read all about these here. But the basic idea behind them is simple. Bodies within the same group do not collide with each other. Bodies that do not share at least one layer (layer being a bit in a bit mask) do not collide with each other. And finally, bodies for which there doesn’t exist a collision handler (defined by a function pointer for a bodyType-bodyType pair) do not collide with each other. Chipmunk creates a default collision handler that is a catch-all handler for all bodies that satisfy the group and layer requirements. This default handler handles all collisions that trickle down to it. In Doodle Blast, I’ve overridden this behavior such that no bodies collided by default unless there was an explicit collision handler defined. Then, I’ve split all objects within the game into groups and layers as follows:
Item Group Layer
Player guns 1 PLAYER
Friendly fire 2 ENEMY
Enemy fire 3 PLAYER
Enemies 4 ENEMY | PLAYER
Bonuses 5 BONUS
I’ve added a collision handler (using the same generic function pointer returning “yes, please, handle this collision”) for the following types of bodies:
Player <-> Enemy
Player <-> Enemy Fire
Enemy <-> Friendly Fire
Et voila! Now I knew about all the collisions I cared about without the overhead of calculating too much of anything else.

There was one more trick. I wanted the guns to stack neatly on top of each other. So, I gave each gun a stacking shape (essentially a rectangle), didn’t assign any group to it (meaning, they all collided with each other), placed them all into their own collision layer (meaning, they all collided with each other but nothing else), and added a generic StackingShape <-> StackingShape collision handler to deal with the guns bumping into each other.

That’s it. These assignments essentially gave me all of the game interactivity for free. Chipmunk was my friend.

I added a couple of more tweaks here and there (scores, bonuses, ...) and, at the end of the day, this was the result so far: