Monthly Archives: May 2017

Performance of browser-based games

Until recently, performance of browser-based games for mobile devices has lagged significantly behind desktop performance. If you wanted to create a Canvas-based mobile game, performance was terrible and you needed to build your game around the limitations of the platform. Developing a usable game meant using tricks like scaling up from very low resolutions or doing partial screen updates instead of full refreshes, meaning your game design was limited by the platform’s weaknesses rather than your creativity.

Luckily, this has changed. Browser vendors are rapidly improving their mobile performance:

  • iOS5 now ships with Nitro Javascript
  • Chrome for Android browser is now available on Android 4 (Ice Cream Sandwich)
  • Windows Phone 7 Mango launched IE9 mobile with hardware acceleration

All feature a GPU hardware-accelerated HTML5 Canvas element and both feature multi-touch support inside of the browser, a must for any but the simplest games. While Chrome for Android still have some significant work to do on Canvas performance, this now seems like an inevitability rather than a hopeful prayer.

Developing HTML5 games that work in the mobile browser comes with its own special set of requirements. You’ll first need to have an idea of the number of sprites you can push on the screen at once. Next you’ll want to maximize your game to the size of screen so that users don’t have to squint to play your game. Next you’ll need to add touch controls so the game will be playable without a keyboard. Finally you’ll want to consider adding a number of pieces of meta-data to allow your page to be used a home-screen application and have it show up with the right icon.

Performance Considerations

While mobile HTML5 game performance has increased significantly, you do still need to be aware of the limitations of the two dominant platforms: iOS and Android.

You have two primary options when building an HTML5 game: either build it with Canvas or use CSS sprites. For example, before iOS 5, you’d achieve much better performance in general using CSS sprites, provided you weren’t moving too many of them each frame. This was (and generally still is) the case with Android. Browsers have been optimizing the rendering of HTML elements for a long, so unless you are moving a full page’s worth of tiles and sprites, CSS sprites are still something to consider.

Now with hardware acceleration, Canvas performance has reached a level where where full screen action games at CSS pixel resolution are possible.

The rub is that most of these devices have resolutions that far exceed CSS pixel resolution. In iPhone 4, the resolution of the retina display exposed to web developers was unchanged at 320×480, while the actual screen resolution is 640×960. Since the resolution of the canvas tag is independent from how it’s rendered on the screen, you can create a full resolution canvas, set it to 320×480 CSS pixel dimensions and be pushing 4 times as many pixels through to the display. This will look crisp and nice, but you unless you are doing partial screen refreshes, pumping that many pixels through the Canvas tag is currently out of the reach of HTML5 mobile games.

These limitations means that as of the current generation of devices, you should be targeting a CSS pixel resolution in your game (many native apps still don’t necessarily all have Retina-display scaled assets, so this shouldn’t be viewed as a huge failing).

The good news is that at this resolution you have a little bit of breathing room with how much you render on the screen. I’ve written a simple test script (runnable at http://cykod.github.com/mobile-html5-tests/) that renders a number of moving 30×31 pixels sprites onto an area 320×320 pixels in size using a number of different methods (including CSS sprites and plain Canvas). Running this test script on a iPhone 4, an iPad 2 and a Galaxy Nexus in Chrome for Android results in the following performance for CSS sprites (background images) and Canvas sprites:

All three devices are able to draw over 100 sprites per frame (with a full canvas clear) and render at least 30 fps. While 100 sprites is not a limitless number of sprites, it’s enough for many uses cases. For games with tiled backgrounds, you’ll still want to prerender to offscreen canvas buffers instead of redrawing every tile each frame, but a fullscreen animated game is certainly doable.

Given that every platform can still render double digit frames per second at 1000 sprites per frame, you have some extra leeway to do some significant pre-rendering and offscreen rendering every few frames without grinding your game to a halt. The rest of this article will assume you’re working on a Canvas based game as that’s where the performance boosts are going to be. If you’re working on a CSS sprite-based game, some of the pieces (such as canvas resizing) won’t apply, but much will still be applicable.

Viewport Considerations

Once you’ve got an HTML5 game spec’d out within the performance capabilities of the platform (or are converting an existing game for mobile play) you’ll need to consider how that game will actually look and play on mobile. Many web games on the desktop are generally confined to a play area of a specific size with additional stuff (ads!) wrapping around the play area.

On mobile, this won’t fly. Mobile devices have such limited screen real estate as it is that when a player is playing your game, it behooves you to maximize the play area to the extent that you can. This might seem easy in principle, but since different devices have different resolutions and aspect ratios there’s often only so much you can do.

Your main options are either:

  1. Resize the canvas to fill the entire screen.
  2. Resize the canvas to fill majority of the screen, keeping the existing aspect ratio.

Option 2 will give you infinitely less trouble than option 1, as it means your game code doesn’t need to worry about having a different sized playing area depending on the device. On the flip side, it also means you’ll be constraining the viewport of your game smaller than the full size of the device. For some games you’ll want the size and aspect ratio of the game to stay consistent so that enemies appear and disappear in consistent ways. For a 2d platformer, you might consider going with option 1 as adjusting slightly the amount of the level that the player sees while playing isn’t going to dramatically affect gameplay but will make the game look (and play) more like a native game.

Game Code Organization

At Bocoup, my colleagues and I often laze about in antique leather armchairs, sipping Mai Tais, waxing rhetoric about important issues-of-the-day including international politics and automatic semicolon insertion. One thing I find fascinating is how people working on different types of projects have different wisdom to share: best practices for jQuery plugins are different than those for Facebook apps, and tips for Backbone.js ecommerce sites may not be useful when developing real-time strategy games.

What I’d like to share in this article is some code organization tips and tricks I’ve learned while making HTML5 games. I’ve tried to keep them as generally useful as possible, but you’ll definitely get the most out of this if you make games like I do.

First I’ll discuss organizing JavaScript code into files and modules. Then I’ll talk about code sharing approaches such as component systems. Lastly I’ll share some ideas for writing data-driven code in games.

Files and Modules

It should go without saying that a large application all stuffed into one file is a maintenance nightmare. Still, even now, the logistics of organizing JavaScript in separate files are being ironed out. First let’s look at the file issue itself, then the more complex issue of what sorts of modules those files contain.

Many Files in Development, Concat in Production

When setting up a new JavaScript project, I recommend using grunt, a build tool that has built-in tasks for concatenating all your files into one, then minifying the result. You want users to end up downloading just one minified JavaScript file. This is great in production, since it reduces HTTP requests and download sizes. In development, it’s not so good: having readable code in separate files is necessary for efficient debugging.

I recommend having something like this in your index.html:

This way you can comment out app.js and uncomment the source files for easy development.

However, this isn’t ideal. One thing you might do is modify your build process to have options to build for development or for production, saving you the effort of manually commenting / uncommenting lines. No build tools do this out of the box as far as I know, but for some projects this extra effort of customizing your build process may be worthwhile.

Source Maps

Google Chrome has a cool new feature called Source Maps that solves this problem. When you use a JavaScript concatenator/minifier that supports Source Maps, the compiler will add a comment to the code that refers to the source map (a header can also be used). The source map contains all the necessary information for linking from the compiled code to the source file. As a result, development tools that support Source Maps will understand what file some given code originally came from. There is no longer any issue debugging / developing with minified code.

Right now the Closure compiler and Google Chrome are the only compiler and browser that support Source Maps, so it can only be used on certain projects. Still, if more tools start to support it, this may be the future of debugging JavaScript.

IIFEs and Namespaces

Now that you have a build process that intelligently handles multiple files, what actually goes in those files?