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.

About Josh Tynjala

Josh Tynjala is a frontend developer, open source contributor, bowler hat enthusiast, and karaoke addict. You might be familiar with his project, Feathers UI, an open source user interface library for Starling Framework that is included in the Adobe Gaming SDK.

Discussion

  1. Pedro Canterini

    Very exciting mate! I hope you get to share more of the process with some code examples when you get more confortable with html5+JS.

    cheers

  2. Shawn

    Great write-up, we also felt the pain of Audio implementation in our latest project. Both chrome and IE9 have a limit of around 40 files, and since IE9 doesn’t a support Audio(), DOM Injection of ended up being the way to go, and basically you have to whittle down your sound instanced to ~37.

    Regarding AD Support in AIR 2.5, it is actually available:
    http://www.smaato.com/

  3. Josh Tynjala

    mico, the editor I use for most quick and dirty editing is Notepad2. If I start doing more HTML5 dev, I’ll probably look for something a bit more robust. Maybe Aptana or something that uses TextMate bundles (I’m on Windows).

    Shawn, thanks for the insight on ~37 audio instances. That could be exactly the issue I’m seeing with Chrome. I’ll bet as new sounds are loaded and played, the earliest ones stop working.

  4. ash

    Great write up.

    There seems to be too much choice in the HTML5 world. Too many libs, all at different maturity levels with different API design decisions, always changing. Too much choice can be crippling, whereas Flash is one tool with “one” API.

  5. Josh Tynjala

    I’m not sure I agree with that, ash. You’ve got Flash Pro, Flash Builder, Flash Develop, IntelliJ, and FDT all off the top of my head, and that’s just AS3 support. I can think of a couple more that were commonly used back in the AS2 days. We have a lot of choice, and most of the Flash devs I know don’t even use Flash Pro for daily work (which I assume is your “one tool”). The others are all equally divided among the editors.

    Too many libs is kind of a strange assertion too, or do you mean too many that do the same thing? Even in AS3, we have an excess of choice. I remember once looking for a physics library, and there were so many I was overwhelmed. All were somewhat based on the ever-popular Box2D, but each had its own unique variations. Even worse is the situation with tween libraries. It seems every developer tries to make their own once they reach a certain level of experience. I know I did. It took me forever to decide on one I liked.

  6. Tomas

    It’s nice that HTML5 evolving but its slow, inconsistent and complex at the moment.

    Doom 1 is made in Flash, lightyears from html5/javascript?

  7. Louis Stowasser

    Nice article. Please don’t hesitate to email me about any changes to Crafty you think are important. All of these points will be turned into issues that I can hopefully fix by v0.3. Any others you can think of would be greatly appreciated.

    Great game!

  8. igniz17173

    I faced the same problem with audio too. But u can actually do a trick to allow multiple playback of that audio file.

    Create more than 1 buffer of the sound file whenever u play an effect sound & push into an array of playing sounds. Remove the buffer from the array when it is played completely. Remember to remove any reference to the buffer too to allow for GC.

  9. craftyjslearner

    I want to study the code further. Is there a way that I can download all the associated files without minification?

  10. Josh Tynjala

    Keith, at the time I put this together, Playtomic was planning to charge per casual game (with one free, as I mentioned above) and they had special pricing for social games. It looks like they’ve changed their plans.

    Thanks for letting me know that the game isn’t working. Playtomic is actually returning a 404 for the older version of their JavaScript API. Lovely.

  11. Marc

    Regarding re-rendering when x & y change. I think, though I’m not 100% sure, calling .attr({x: 150, y: 120}) will set both x and y before re-rendering.

  12. Bernhard

    HI, very nice writing about HTML5 and the comparison to Flash. Maybe you are interessted in the thing i have done over the last week. I ported most of the Flash Display List (and Sound classes + more to come) to the new programming language Dart, which compiles to JavaScript. If you are an ActionScript programmer, you will ike Dart very much.

    Check it out here: http://code.google.com/p/dartflash/

    There you can find a link to a game which was ported from Flash to HTML5, using Dart and the library i did.