I'm creating a game in jQuery, where I use about 10000 32x32 tiles. Until now, I have been using them all separately (no sprite sheet). An average map uses about 2000 tiles (sometimes re-used PNG's but all separate divs) and the performance ranges from stable (Chrome) to a bit laggy (Firefox). Each of these divs are positioned absolutely using CSS. They do not need to be updated every tick, just when a new map is loaded.

Would it be better for performance to use spritesheet methods for the divs using CSS background-positioning, like gameQuery does?

Thank you in advance!

  • 3
    \$\begingroup\$ Where the hell you need 10 000 tiles for map? I suggest that you dont upload/draw all the map on user side. Show just a portion, that is visible. When user moves, load next section. The way every 3D graphics works. \$\endgroup\$ – Deele Nov 2 '11 at 23:44
  • \$\begingroup\$ An average map uses 2000 different tiles, or just 2000 total tiles? How big are the maps you are creating? \$\endgroup\$ – Nick Larsen Nov 3 '11 at 3:32
  • \$\begingroup\$ Have you considered using one or a few larger images as a background and performing polygonal collision detection for boundaries? \$\endgroup\$ – SAHornickel Dec 19 '12 at 15:15

My suggestion

Too many small PNGs will add a lot of network overhead (because of the size of the HTTP requests, but also the PNG header, and, probably even more importantly, the inability to compress efficently). On the other hand, one very large PNG has the drawbacks that it takes some time to load, and needs to stay permanently in memory (40 megabytes for 10,000 tiles) in a continuous chunk of memory.

I recommend the middle ground: several reasonably sized PNGs, for instance 1024 tiles of size 32×32. Maybe grouped by theme (for instance, a PNG with forest tiles, one with mountain tiles, another with city tiles -- I don't know the theme of your game, but you get the idea).

Note about cache efficiency

Because of memory access efficiency, you should never make your spritesheets too wide. Blitting tiles from a 128×8192 image will always be faster than blitting from a 8192×128 image.

Imagine you want to blit the first tile in a 8192×128 image. For the sake of simplicity, assume 1 pixel is 1 byte. The first two lines of pixels are laid out this way (cells contain their byte number in memory):

│  0 │  1 │...│ 31 │   ....   │ 8191│ 1st line of pixels: bytes 0 to 8191
│8192│8193│...│8223│   ....   │16383│ 2nd line of pixels: bytes 8192 to 16383
│ .. │ .. │...│ .. │   ....   │ ... │

So in order to blit the first line of the first title, the browser engine will retrieve bytes 0 to 31. To blit the second line, it will retrieve bytes 8192 to 8223, and so on until the 32nd line where bytes 253952 to 253983 are retrieved.

The total number of processed bytes will be 32×32. However, the total memory range is more than 253984 bytes. On a modern CPU, this means 32 or 33 cache stalls. In contrast, if the image was 128×8192, the memory range would be only 4000 bytes, which means no more than two cache stalls.

Because today's CPUs are very fast, cache stalls are very expensive and hang computations. So using a 128×8192 image instead of a 8192×128 image is potentially 8 times as fast, in theory at least. In practice this will depend how the blitting is implemented: it is possible that the underlying engine itself splits images into tiles to reduce the problem.

This isn't easy to explain correctly and I didn't expect to elaborate much. I hope it makes sense!

  • 4
    \$\begingroup\$ "Note also that because of memory access efficiency, you should never make your spritesheets too wide. Blitting tiles from a 128×8192 image will always be faster than blitting from a 8192×128 image." - nice curiosity, would you elaborate please? : ) \$\endgroup\$ – Grimshaw Nov 2 '11 at 18:34
  • \$\begingroup\$ @DevilWithin: I have tried to explain the problem; let me know if I am being clear enough! \$\endgroup\$ – sam hocevar Nov 2 '11 at 20:12
  • \$\begingroup\$ The cache efficiency stuff is fascinating. Do you have any numbers on the difference this makes with regard to framerate? \$\endgroup\$ – Gregory Avery-Weir Nov 2 '11 at 23:27
  • \$\begingroup\$ Whether it is a problem, looks like implementation specific, but if API like OpenGL act on textures that way, it sure is important to take that into consideration, thanks :) \$\endgroup\$ – Grimshaw Nov 2 '11 at 23:36
  • 2
    \$\begingroup\$ @DevilWithin: what I wrote is only valid for a CPU -- a GPU, being massively parallel, has very different cache settings and will store textures using its own internal format, optimised for random access. This is the reason why square, power-of-two textures are recommended in OpenGL, and I would follow that rule for tilesets, too. \$\endgroup\$ – sam hocevar Nov 3 '11 at 0:00

One huge spritesheet is (likely) going to give you better performance, simply because one of the biggest causes of lag is the round trip from browser request to server to browser. 10,000 HTTP calls is going to take much, much longer than 1 HTTP call that returns a file that is 10,000 bigger.

There might be other things you can use to decrease lag, depending on the structure of the game and the HTML you're creating.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.