Porting QWOP from Flash to Luxe

sign up sign in

A Postportem

Everyone's been talking lately about the impending death of Flash. Mozilla blocked the plugin by default in its browser, and Facebook security chief Alex Stamos called on Adobe to set and end-of-life date for it. Everyone's busy porting their websites, ads and games over to HTML5, which is supposed to replace Flash as the place for rich media on the web.

The thing is, although everyone hates flash for eating CPU cycles and running unskippable ads, it's really great as a platform for browser games, for two reasons. First, it's a VM that runs exactly the same everywhere it's installed, so you can forget almost completely about compatibility issues between browsers and operating systems (except Linux), which can be a massive source of pain for web development in general. And second, because everyone already has the plugin installed, the output files are really small, which is wonderful if your website gets a lot of traffic. QWOP, which has had well over 100 million visits, weighs in at a mere 148kb, including all the art, code and sound. For comparison, the minimum size of a HTML5 game made in Unity is between 10 and 20 megabytes, so if QWOP was written in Unity it would have cost me literally tens of thousands of dollars in hosting fees over the past year alone.

Anyway, while Flash will linger in our desktop browsers for a good many years to come, the rise of the mobile web has meant that it no longer makes sense to make games in Flash, and if you have a high-traffic game like QWOP written in Flash it's probably about time you ported it over to HTML5.

Porting QWOP

QWOP is a weird game. It's written in Adobe's Flash IDE, and a lot of the art is designed as Flash vectors, which helps to save on space. The look of the game depends on the fake 3D lighting on QWOP's body, which I achieved using the Flash IDE's built-in 'gradient bevel' effect, and the game feel depends on an old buggy port of Box2D.

If I was porting a Flixel game to HTML5 I would probably use HaxeFlixel, but I wanted something more flexible, which could build to a very small size, and that would allow me to be as faithful as possible to the original flash version, so it could be preserved and still playable even as the Flash install base dwindles away.

With all this in mind I decided to port QWOP to Luxe.
The minimum build size for Luxe is about 120kb, which is not much larger than Phaser's new minimum build size (80kb) while supporting a lot more functionality. And Luxe makes it pretty easy to recreate the look of the flash version of the game.

Art assets

QWOP luxe vs flash

I couldn't face trying to recreate all the vector art and layouts in Luxe via code, but Flash has a handy feature in the IDE which allows you to export any visual elements as a spritesheet, complete with a standard TexturePacker-style JSON atlas, which Luxe has an importer for out of the box. I baked out all the intro and endgame screens and UI elements into spritesheets, along with the player sprites. It doesn't look as crisp as the original vectors (especially on high-DPI screens) but it has a lot less compression artifacts, and I still managed to pack all my assets down to about 200kb, which is pretty good.

For the physics I used the Haxelib port of Box2D, which is an almost verbatim rewrite of BorisTheBrave's Flash port of Box2D, which is what the Flash version of QWOP uses. Unfortunately, QWOP depends on some weird bugs from the 2008 version of Box2D, so I had to back-port some of the code to include the old bugs. Still, Haxe and AS3 are so similar that it didn't take long.

In the Flash version of QWOP, all the bodies and joints are placed visually using the Flash editor, using Jesse Sternberg's WCK system. I wrote a little script to spit out all the positions and properties of the bodies in the Flash version, so I could paste them into Luxe, and that worked fine. In the new version, each physics object is a Luxe sprite with a simple custom physics component attached to it, that synchronizes the movement of the sprite with the Box2D physics body. Luxe has this nice built-in entity-component system that makes it easy to extend the functionality of the base classes without having to create a subclass (although you can do that instead if you want to).

Player visuals
The original gradient-bevel effect is not pixel-shader friendly. It works by computing the distance from any given pixel to the edge of a sprite, and then calculating a surface normal based on that distance. But the visual effect is basically exactly the same as DOT3 bump mapping with a pre-computed normal map. I used SpriteIlluminator to quickly generate a normal map for the player's spritesheet, and wrote a GLSL shader to recreate the look of the original as closely as I could be bothered to. Writing shaders for Luxe is really super easy and nice, with none of the weird proprietary stuff that you have to deal with in the Unity system. If a shader works in ShaderToy then it probably works fine in Luxe.

Touch input
The one real change I wanted to make between the old and new versions of the game was that I wanted it to work without a keyboard, since it would now be able to load in a mobile browser. I set up some touch handlers to check if people were touching the sprites on the screen, so you can now play by touching the virtual keys.

Work flow
I've published two web games in Luxe now (the other one was this little experiment I wrote for the students in my game-a-week class at NYU). It's does pretty much anything you might want it to do for a 2D game and it has an enormous array of useful stuff built into the core API. But the best thing about it is that it's just aesthetically very nice to work in. You stay in Sublime Text the whole time, and when you hit CMD-B you are just instantly playing the game in your browser or in a native window. It's not messy in the way that visual systems like Unity or Unreal can be, and it's not heavy in the way that code-only systems like OpenFrameworks or Cocos2D can be. It gets out of your way as much as possible and lets you just focus on making your game.


Actionscript to Haxe

Before I got started writing games in Luxe I had never used Haxe before. If you've ever used a sort-of-strictly-typed, garbage-collected language before, like C# or Actionscript, Haxe is not really any different for the purposes of writing browser games. It has a weird syntax for loops, and it has a nice built-in Map data type, but the process of converting Actionscript 3.0 over to Haxe is totally painless. Don't be scared of Luxe just because you don't know any Haxe!

Headaches unrelated to Luxe:

HTML5 game development has gotten a LOT smoother over the past year or two. Browsers now mostly support webGL, which performs great on mobile platforms, and sound support is now less of a mess than it was. With a week's work I had a nice port of QWOP running perfectly in its little HTML canvas element, and it works exactly the same in every popular desktop browser with one or two minor exceptions. But while actually porting QWOP over to Luxe was painless, the process of getting it to look right in a mobile browser window is still a bit of a nightmare.

Every phone OS, browser and hardware combination tries to position and scale the 'viewport' differently when a page is loaded or when the screen is rotated. You can try and control these things using responsive layouts or the viewport meta tag, and Luxe has some features that help with this, but it's extremely difficult to get it working right on every system, especially for a game where you need to disable certain accessibility features like hold-to-select or pinch-to-zoom, since they mess with the game. Some browsers allow you to disable these features, others don't. Some browsers stop respecting your viewport settings as soon as you rotate your device. It's — to be blunt — a shitshow, and it doesn't look like getting better anytime soon.

Luxe is Agnostic

I teach people how to make digital games at the NYU Game Center, and lately we've been getting people started with HTML5 browser games, since it's a nice way to keep the scope of games small and make them easy to test and publish. For that purpose, we use Phaser, although there are other great options like Game Maker or HaxeFlixel. When I'm teaching absolute beginners I look for a framework that does a small number of things in a rigidly uniform way.

As a developer though I want the opposite of that — I want an agnostic framework that lets me do anything I want, however I want to do it. Luxe is built like that. You can easily replicate the usage of almost any popular game framework in Luxe. Part of that is down to the alpha status of Luxe, and I know Sven is still iterating on the architecture and figuring out what works best, but part of it is a core philosophy of the platform.

Agnosticism is nice if you already have a coding workflow you're comfortable with, and you want to bring that existing workflow to Luxe. And it's nice if you dislike certain programming patterns for aesthetic reasons and want to steer clear of them.

But when you're porting a game from another system or platform, agnosticism is particularly important. It means you can keep the code structured more or less exactly as it was in the original version, no matter where it came from. If you're porting from Unity you can keep your Entity-Component structure. If you're porting from OpenFrameworks/C++ or Flixel/AS3 you can keep an object-oriented structure.

You could even build a beginner-focused sub-framework in Luxe! Once it comes out of alpha and gains wider adoption, we will probably see people use it in that way, just as Terry Cavanagh's new TerryLib library provides a narrow, rigid subset of OpenFL for absolute beginners.

Final words

Browser hassles aside, this was a great experience. Luxe is still in alpha, but I strongly recommend it as a platform for porting games to HTML5 or native targets from other systems, and for writing 2D games in general. I don't think my needs are unique: I want a flexible, powerful multiplatform engine that builds small and lets me work clean. Luxe is that.

Play the luxe build of QWOP right here.