Monthly Archives: January 2011

Indie Flash Game Development: 2010

About a year ago, you may remember that I shared my revenue numbers for indie game development in 2009. I had big plans for Bowler Hat Games in 2010, but I guess I spent my time going in the wrong directions. Here’s a look at how my business is doing one year later.

The Breakdown

In total, game development earned me $20,009 in 2010. That’s about 32% lower than last year, and I spent an equal amount of time developing games during both years (I worked on other projects for about four months during both years). Revenue is divided between four sources, game contracts, mobile sales, advertising from existing web games, and non-exclusive licensing. I didn’t create any new Flash web games, so there were no primary sponsorships this year.

2010 Revenue Breakdown

As with last year, most of my income came from contract work, earning me $15,900. I spent the least amount of time on those projects—maybe a month and a half. Continuing ad revenue from the three Flash games I released on the web last year earned me an average of $198 per month. Mobile app sales brought in an average of $131 per month. I sold one non-exclusive license of a Flash web game for $150. In total, that’s an average of $1667 per month, with contract work covering the vast majority of that amount. Living in the California Bay Area, that covers my rent for a one bedroom apartment and groceries, but between other bills and, of course, income tax, I’ll need to make a lot more if games are going to cover my expenses.

iOS and Android Games

At the end of last year, I had converted two of my three Flash games to iPhone, and revenue was already proving to be modest at best. This year, I finished porting my third Flash game to iOS, and I released some updates for each of them. Sales never picked up much, though. Additionally, I removed my games from the App Store for a couple of months while Apple was being stubborn about the Flash Packager for iPhone, so there was a bit of time mid-year where I received no income from selling apps.

Adobe released AIR for Android this year, and I had all three of my mobile games ready for sale at launch. Unfortunately, I had them ready for several months before I could actually sell them. Unlike Adobe’s solution for iPhone, which embeds the runtime into the app, the Android version of AIR is a separate install, so I had to wait for the official release. I’m finding that sales of my games are lower in the Android Market than in the iOS App Store. In December, iOS sales were about five times higher than Android sales. It’s too bad because creating mobile AIR games on Android is actually a lot of fun.

Mobile isn’t a walk in the park

Ultimately, I believe that I spent too much time on mobile this year. I would have been better off designing new games and getting sponsorships instead, or maybe I should have started exploring downloadable desktop games or microtransactions. Last year, I said that sponsorships didn’t seem like they could earn me enough (at least for the type of games that I make), but mobile has proven to be an even harder nut to crack. It’s probably my lack of marketing skills. With sponsorships, I can visit FlashGameLicense and have a community of portals and other sponsors who are there to pay for games like mine. With mobile games, I don’t have a central source to locate my audience. At best, I know that players of the web game might be willing to buy a mobile app, but beyond that, I’m a little lost.

I’m still waiting on a supported advertising solution for AIR mobile. I don’t want some API that the ad network says works for “everything else” while only native code gets a real SDK. Free versions of games that are ad-supported can be a great way to get players to consider the paid version while still bringing in revenue. I’ve considered the possibility of converting my mobile games to HTML and JavaScript because I know there are frameworks that integrate better with native libraries that provide advertising and other services for games. However, with such low revenue on mobile already, I’m worried that I might be wasting even more time by trying that. It will require more development and testing than my recent HTML5 port of Gridshock, which was more of a fun project for the holiday break than a serious one. I was able to take shortcuts. With a paid product, shortcuts are not an option.

2011

I’m probably not touching mobile for a while, except maybe for fun weekend projects. Even so, I very much want to play with tablets at some point, but I think I’ll wait until some are released with Android Honeycomb. All the hardware coming out is kind of overwhelming. As an indie developer, my wallet cringes at the idea of ensuring I own even a minimal collection of test devices.

As for what I will be doing this year, I intend to start out with a sequel to Gridshock. Hopefully, with Gridshock’s success as evidence, I can get a better sponsorship deal than the original. From there, I may consider a desktop version that combines both games. However, I kind of want more than two game modes in a desktop app, so I may explore other ideas for sequels first. I might include an exclusive game mode or two in the desktop app to ensure that it provides enough value over the free versions. That’s still brewing for the moment. Right now, I just want to focus on finishing a game to be sponsored.

With lower numbers in 2010 than in 2009, I’m feeling a little down. At the same time, though, I’ve found myself surprisingly motivated over the last couple of weeks. I spent one night coding until 4:00am. I’m attacking my to-do list with enthusiasm every day. Last year’s numbers, I think, are helping me work harder because they’re more frustrating to me than depressing. I want to make Bowler Hat Games a success, or at least ramen profitable. The way I did things last year clearly didn’t work, so I’m just going to try harder and see if I can figure out what works better. Wish me luck.

Flash to HTML5: Gridshock Remade

Over the holiday break, I decided to spend some time on an interesting project. I wanted to remake one of my Flash games on a different platform. Don’t get me wrong. I thoroughly enjoy developing for Flash Player and AIR. I just wanted to try something new. A little cross-training to give me a fresh perspective. Over the last several months, this idea has been stewing a bit. I considered things like going all out and learning Python to try pygame, but that seemed like it might take up a little too much of my time. Ultimately, it seemed that HTML5 and JavaScript were probably the best way to go due to JavaScript and ActionScript having a similar language heritage.

The result of my efforts over the last couple of weeks is Gridshock in HTML5:

Screen shot of Gridshock in HTML5

Gridshock, a Flash game remade with HTML5

Picking a Game Library

Not too long ago, I discovered Crafty, a JavaScript library for games. The documentation describes components that are simple and to the point, and I felt like I already had a pretty good understanding of the library after a quick glance over the APIs. As of this writing, Crafty is still at version 0.1, so it’s not exactly mature. Let’s be honest, though, most JavaScript game libraries are brand new anyway. I attribute that to IE9 finally getting Canvas support. Anyway, like I mentioned earlier, I wanted to branch out and try game development outside of Flash, but I have other projects I need to get to soon, so I needed to pick a library as a foundation so that I didn’t get stuck on low-level architecture decisions. Crafty seemed like the right choice for me.

Crafty logo

Crafty, a JavaScript game library

Very recently, Grant Skinner released Easel, a JavaScript graphics library based on the display list in Flash. This, of course, should be an obvious choice for the conversion of a Flash game. It’s hard to explain what made me stick with Crafty (which I discovered first). I think my decision ultimately came down to the fact that I wanted to work with a library created by someone from outside the Flash community. More chances to learn new techniques. That said, if I ever make another JavaScript game, Easel will be a top contender so that I can make comparisons and decide on which one I like best.

Other Libraries

Playtomic is way ahead of the curve. In addition to Flash support, they offer a leaderboards API for HTML5 too. I was pretty excited to discover them one afternoon because, otherwise, I would have only stored high scores locally. I am not a backend guy, and I have zero desire to set up high scores on my server. Mochi Leaderboards are great for Flash, and it appears that Playtomic is a great way to go for HTML5. Please note, however, that Playtomic is currently only free for one casual game. However, the flat-rate prices don’t seem too steep.

humaneDate() is a nice little JavaScript function for converting dates to something that’s a bit more readable (like “2 hours ago”). Playtomic provides dates like this automatically, but I needed humaneDate() for the local player’s high scores that I store for convenience. Unfortunately, the written format is a little different between the two. The non-humane date returned by Playtomic isn’t an exact time, either, so I can’t accurately reuse that with humaneDate(). If this were more than just a learning exercise, I would have modified humaneDate() to match Playtomic’s output.

I ported GTween to JavaScript. It’s my tween library of choice in Flash, and the Flash version of Gridshock uses it, so I figured it would save more time if I made GTween work in JavaScript instead of converting to an existing JavaScript tween library. Edit: gtween.js on Github.

Crafty logo

Modernizr, a JavaScript feature detection library

Modernizr offers an excellent way to detect modern browser capabilities and display alternate content if the current browser doesn’t stack up. If you load Gridshock in an older browser, you’ll see a message that suggests upgrading and links to the Flash version. Modernizr helped me detect if JavaScript is enabled, and whether the browser supports HTML5 Audio, Canvas, and Local Storage. I also included some manual checks for JavaScript features I needed, like defineProperty(), which is JavaScript’s version of getters and setters.

From ActionScript to JavaScript

JavaScript is a different beast than ActionScript 3, as we all know. They may have originated in the same place, but there’s a certain extra comfort AS3 provides with classes, strong typing, and the automatic compiling during development in Flash Builder.

Still, though, there’s something kind of elegant about JavaScript. It’s looser, but I thoroughly enjoy playing with closures and things like that. In fact, after I spent a few months a couple years ago writing a wrapper for my Flash charts to make them available to YUI JavaScript developers, I started using closures in ActionScript quite a bit more. This previous experience made conversion of Gridshock to JavaScript a lot easier.

Image of Xzibit, from the 'Yo, Dawg' meme

You dawg, I heard you like functions, so I put a function in your function…

Crafty has a component system that creates “entities” with mix-ins. If you add the 2D component, the entity will have x, y, w, and h properties, along with some methods for working with them. If you add the canvas component, the entity will draw itself on Crafty’s stage. If, on the other hand, you add the DOM component, it will add an image to the page’s DOM on top of the canvas.

I quickly started creating new components for Crafty. One for alpha was the most obvious because I like fading things in and out (like the lights on the grid). Another, that I called “autoz”, I created to automatically manage depth. Similar to older versions of Flash, I discovered that I was forced to manage depth manually with Crafty. This simple component kept me from tearing my hair out when I discovered that the order of drawn entities wasn’t always consistent.

Both of those additions mixed-in with existing components right away, and I found myself enjoying this approach over inheritance. In my experience, inheritance in JavaScript can be a pain. It’s certainly doable. I liked YUI’s implementation back when I was using it. However, I found myself embracing composition and mix-ins more easily than I would in ActionScript 3. I think a lot of developers moving to JavaScript from a language with classes should take a moment to consider living without inheritance, if only to learn something new from the experience.

HTML5 features

While creating Gridshock, I worked with three features of HTML5—Canvas, and Local Storage, and Audio.

HTML5 Logo

Canvas

I actually did very little coding directly with Canvas. Crafty had most of that covered. There was a bug or two in Crafty that I needed to workaround, but my tweaks were minimal.

To be honest, I think the Canvas drawing implementation in Crafty is a nice start, but it’s certainly not the most optimal. I noticed my laptop’s fans powering up a lot whenever I was testing Gridshock. Crafty draws sprites too often. There’s no invalidation system to draw all changes in one go on each frame (yes, Crafty has an enterframe event similar to the one in Flash). Instead, if I change the x position of a sprite, it draws to the Canvas immediately. Then, if I change the y position on the next line, it draws again. For my needs, with a simple casual game like Gridshock, that’s fine. However, I hope that the author will look into improving this in the future.

I didn’t run into any cross-browser issues with Canvas.

Local Storage

Local Storage worked like a charm across all the browsers I tested on. If you’re unfamiliar, Local Storage is similar to Flash’s SharedObject. However, it’s a bit more primitive. Everything is stored as a string. To store complex objects, you need to encode to JSON. Not a difficult workaround there, and that’s probably what the HTML5 working group intends.

I used Local Storage to store a list of the player’s own high scores, and I store the game’s settings with it as well (sound effects and patterns mode, as found on the Options screen).

The only cross-browser issue I ran into here was that Date objects weren’t encoded to JSON the same way in some browsers. That’s the JSON implementation, though, not Local Storage. Regardless, the workaround was easy. I just stored the UTC date string instead. That’s easy to parse with new Date(utcString).

Audio

Oh man, getting audio to work cross-browser is a major pain. Canvas and Local Storage are both pretty much fully baked in all browsers at this point, from my experience. The audio situation, on the other hand, is still very raw.

Image of guy with bull horn

I did not have a protective suit like this. Photo by vacantfever.

Crafty has a very simple audio API that wraps HTML5 Audio, and it seems to work consistently. However, it didn’t meet my needs. I need to play a sound effect every time the player clicks on the light grid. A single Audio instance can only play itself once, and you must wait until it is done playing until you can play it again. That means I have to store multiple instances of the same audio file so that I can loop through and pick one that isn’t currently playing.

That’s easy enough. Annoying coming from Flash’s sound capabilities, but easy enough. However, I still ran into other issues. Chrome stops being able to play certain sounds after a while. They’ll play over and over without issue for a couple of minutes, but then I suddenly hear nothing when I try to play them again (while the other sounds continue working). Opera has loud clicks at the end of every sound. Firefox won’t loop audio (that’s why I didn’t include a music track). IE won’t let me create an Audio object and play it right away (or, at least, once a load event fires). Some browsers don’t play the click sound on buttons. It seemed that every variation of the Audio APIs that I tried failed in at least one browser in some subtle, or not so subtle, way. The code I settled on seems to be the most stable, but audio is often delayed before it gets played, and Chrome still stops playing certain sounds sometimes.

In short, Audio isn’t ready for prime-time. The two days I spent hammering on it were extremely frustrating. There’s probably some magical combination of APIs that will fit my use-case in a cross-browser way, but I didn’t find it.

Other Challenges

A couple other things weren’t straightforward.

Preloader

A preloader is easy in Flash. A game SWF is distributed on its own as a single file, so you just have to display some animation on the first frame until the rest of the frames load. In HTML, I had to structure my page so that JavaScript files loaded in the right order, and I had to extend Crafty to preload any images I needed for the sprites before I started the game. Yes, technically the game would run fine if the images loaded as they were needed, but that sort of ruins the experience for a game. Fine for a document, not so much when games need more real-time interaction that could be affected by assets that display too late.

UI Controls

Not super easy, especially when trying to make something work with Crafty. I ended up making my own button and toggle switch components within Crafty’s architecture. When I realized the work required to manually draw a list component for my high scores, though, I felt like gagging. I ended up putting a scrolling div on the DOM with a skinned table inside. This approach felt hacky, since I integrated with Crafty a lot more when I made the other two controls. However, it got the job done. I think if I gave myself some more time, I could have built the list a bit more elegantly and had a nice minimum set of UI controls that could be reused across games. Maybe I’ll explore this more later if I decide to make another HTML5 game.

Screen shot of toggle switch UI controls in Gridshock

After seeing switches like this in iOS, I often choose them over checkboxes.

Parting Thoughts

I enjoyed this little field trip into the land of HTML5. Though I intend to continue making games in Flash, it provided me with a new perspective, and I’m happy to know that I can return to HTML5 with confidence at some point in the future, if I need or want to do that.

For instance, I may be interested in converting my AIR mobile games to an HTML5 mobile framework, like Phonegap, to take advantage of the greater native integration. For instance, I can’t release free, ad-supported versions of my games with AIR mobile because there’s no ad provider that works with the runtime. That’s been very frustrating for me. While I enjoy AIR on Android for easy porting from desktop to mobile, man, it feels limited sometimes.

Anyway, HTML5 feel like it’s nearly ready for casual web games. Currently, there seem to be two reasons to wait a bit longer:

  1. As I discovered, the Audio support in browsers needs work. A lot of it. Audio is important in games, so this is a big one.

  2. Most casual game players are regular people, and they may be stuck on IE at work, or maybe they haven’t yet upgraded at home. Once IE9 is released and has gained a critical mass among IE installations, then I think games may be ready to run on HTML5.

Of course, that doesn’t account for distribution. I don’t expect the HTML5 version of Gridshock to end up on portals. Unlike the Flash version’s single SWF that can easily be uploaded anywhere, the HTML5 version involves an HTML file, a folder of images (which could be put on a single sprite sheet, but that’s kind of a pain without an automated tool), a couple of minified JavaScript files, and a minified CSS file. The HTML, JavaScript, and CSS could be combined, I suppose. However, the images are a bit tougher. I guess if it were a giant sprite sheet converted to a data URI, that would get everything into the single HTML file. Definitely something that game developers and portals will have to think about for anyone who wants web games to move from Flash to HTML5. Unless a dozen portals email me tomorrow to say that they want to feature this version of Gridshock on their sites, I’m not worrying about distribution yet.

Enjoy the game? You can play Gridshock on iPhone and Android. By purchasing the apps and supporting me, you’ll be able to see more in-depth looks at my game development projects, like this one.