Recently, at Humble Bundle we partnered with Mozilla to release the Humble Mozilla Bundle powered by asm.js. The technology behind asm.js allowed us to port nine fantastic indie games into the browser, including hits like Super Hexagon and FTL. People can play these games directly in their browser without plugins, extensions, or huge downloads. It’s super fast, the performance is awesome, and the bundle was a big hit for the developers, Mozilla, and gamers alike.
We’re really excited by the potential of browser-based gaming for the game industry. Being able to click and play directly in the browser removes hassle and presents opportunities for developers to better engage potential players. This blog post is to make you aware of what game technologies are a good fit for asm.js. GDC ‘15 is just around the corner and there could be some announcements that change some of this info. We’ll be sure to post updates over at developer.humblebundle.com as we get them, so for now let’s dive in!
SDL2 is Your Friend
If you’re rolling your own C++ engine, then ideally you are using the Simple DirectMedia Layer (SDL2). SDL2 is designed to provide low-level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D. It also runs natively on Windows, Mac OS X, Linux, iOS, and Android so you might want to think about using it regardless of your asm.js porting plans! asm.js bindings exist for SDL2 meaning that if your games support SDL2 they will transition smoothly to asm.js!
On the rendering side of things it’s best if you’re using an OpenGL renderer, preferably compliant with OpenGL ES 2.0. If you’re unsure which OpenGL version you’re using then it’s probably ES 2.0 compliant if the game is running on a mobile device. In the browser you are actually targeting WebGL, currently a subset of OpenGL ES 2.0. There are some constraints but link options emulate those few features that exist in ES 2.0 but not in WebGL. This will make it easier to get your game up and running and may change as WebGL evolves and improves. If you’re not using an OpenGL renderer and want to bring your game to asm.js then consider porting to SDL2/OpenGL. That will save you a lot of headaches in the long run!
Closed-Source Middleware and asm.js
There’s a good chance that your game is using a popular middleware solution for things like audio playback, UI rendering, physics calculations, etc. If any of your middleware is closed-source or doesn’t provide an asm.js target, then you will need to replace that API before porting to asm.js. Sometimes that’s easy — such as with sound playback code that’s being used for simple sound and music playback. Often it’s very hard — such as with large physics engines that integrate deeply with gameplay mechanics. So what it boils down to is: “Does the middleware you’re using include source, or can it be replaced with something that does?”
However, the future looks bright for a lot of the more popular middleware solutions out there! Most providers are aware of asm.js and are looking at ways they can possibly bring their code over. If you would like to see one of your go-to pieces of middleware brought to asm.js, then let them know via email or social media!
Memory Consumption and Content Size
Running natively in Windows, Mac, or Linux, you might be accustomed to having a LOT of RAM available to your game — gigs of the stuff! In asm.js the available memory ultimately depends on the browser, but in general you will need to keep memory consumption under 512MB. This seems to be a safe upper limit based on the games we’ve ported to asm.js here at Humble Bundle so far.
Right about now, you may be on the verge of a conniption fit wondering how you’re going to fit your game content into 512MB of memory. Well there’s more to the picture so don’t fret! Here are a couple techniques that can be used when dealing with larger games that you might want to port to asm.js:
- Batch your data files. Making your levels/arenas/zones/whatever sliced up into smaller packages has a couple benefits. There is the obvious win of getting your level to fit into RAM. The second big win is that a smaller level can be loaded asynchronously as a packaged file while the previous one is unloaded from memory.
- Stream music and video. This sounds like a no-brainer but it can save even more memory than you think! One game we ported to asm.js had about 280MB of level data; however, we optimized it so that only around 70MB was actually loaded. Turns out the remaining 110MB was music that we were able to stream so that only the active song was in-memory.
- Hand-optimize it! At the end of the day, every game’s data is set up a little bit differently, especially if you’re rolling your own engine. Have you targeted mobile already? If so, then chances are you’ve done a lot of the paring down needed to take your game to asm.js. Have you ever put out a demo version of your game? Then you’ve probably got an idea of how to create smaller levels that easily fit into memory.
After reading this, I hope you have a better idea of how to bring your game to asm.js. What few barriers do exist can be overcome with just a little planning and open communication. The best part is that it’s only going to get easier! With improvements coming to the popular browsers and growing attention being give to asm.js by the middleware providers, the future looks good for more games coming to the browser. And more games is always a good thing!