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 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.