HTML and CSS Reference
Faster Canvas Picking
Colt “MainRoach” McAnlis, Developer Advocate, Google
If you're writing a 2D game in HTML5, chances are that you'll want the user to have the ability to pick an object on the
screen. More specifically, at some point, the user will need to select some item on the screen, or in your game, which
may represent part of the world. We call this “picking” as the user is selecting what object they are interacting with.
Consider, for instance, your standard social time-management game. The user is presented with a 2.5D play area
where bitmaps (or “sprites”) are rendered with some perspective distortion on the screen. For the more advanced
users, you can quickly saturate the play area with these sprites, often stacking many of them together, only leaving a
few pixels visible between overlapping objects. In this environment, determining the picking result of a mouse click
is quite difficult. The canvas API doesn't provide any form of pixel-based selection and the large number of objects
makes it difficult to brute-force the technique. This section will cover how to address performance and accuracy
problems in canvas picking using a few old-school techniques that most of us have forgotten about.
Creating Pickable Objects
For the sake of simplicity, I'll first introduce the most basic form of 2D picking I can, which is simply doing a
point-to-rectangle test for each object in the scene. This type of brute force technique will yield accurate results,
but not the most precise results (I will cover how to get “precise” picking later), especially where two sprites are
overlapping. But before we tackle that topic, let's first start off with a few definitions of objects we'll use throughout
this section, the SpritePrototype and SpriteInstance .
Defining a Sprite Prototype
As with most 2D canvas games, your world will not be populated with millions of unique bitmaps, but rather millions
of objects where large groups of them share similar bitmaps between them. As such, it makes no sense to load a given
image into memory for each sprite that uses it; you'd have duplicate versions of the images, for each instance of the
sprite that exists, sitting around in main memory, which could quickly become a problem.
A much more performant solution is to simply load your images a single time and create references to them as
each instance is created. You effectively cache the prototype images into a large array, which can be referenced
by the individual instances later. The sample SpriteProto class that follows is pretty simplistic. It contains a
filename field, alongside width and height (important later for picking, or in the future when using atlases; see
http://en.wikipedia.org/wiki/Texture_atlas for more information). The most interesting part of this class is
SpriteProto object will then retain a handle to the loaded image in the imgHandle member (see Listing 5-1).