JavaScript Day 20: SpriteSheets

Today we’ll look at a few other things to do with images. We’ll start with a simplified html file:

[php lang=”HTML”]



mar20





[/php]

Note that now we only have the canvas. We will be loading the image dynamically in JavaScript. There’s more than one way to create an image in JavaScript. You can use document.createElement() or use some built in jQuery stuff, or go bare bones and just say new Image(). You then set its source and wait for it to load. This looks like this:

[php lang=”JavaScript”]image = new Image();
image.src = “someImage.png”;
image.onload = function() {
// do something with the image now that it is loaded.
}[/php]

In today’s example we’ll be using the third version of drawImage to implement a sprite sheet. Quick definition: a spritesheet is a large image filled with smaller images. When you display each of the smaller images in the correct order, you get an animation. If you imagine an old celluloid movie reel, unrolled, chopped up, and laid out in a large square, you have the idea of a sprite sheet. While such a contraption would be tough to play back smoothly on a physical device, it’s just a matter of some simple math to make a computer do it.

I’ve used my tool, SWFSheet to generate the sprite sheet you see here:

Full size, it is 512×512, with 6o frames, each one 60×60 pixels.

The third overload for drawImage looks like this:

context.drawImage(image, srcX, srcY, srcW, srcH, dstX, dstY, dstW, dstH);

Args 2-5 define a rectangle in the source image you are drawing. 6-9 define the rectangle on the canvas you want to draw into. The destination in this case will always be the same: 0, 0, 60, 60.

The source rect will start out 0, 0, 60, 60, then move to 60, 0, 60, 60, then 120, 0, 60, 60 and so on until it hits the last frame in the first row. Then it will become 0, 60, 60, 60, then 60, 60, 60, 60, and 120, 60, 60, 60 and so on for that row. We’ll keep track of how many frames we’ve drawn so that when we’ve reached the last one, we start again at 0, 0. Just imagine marching across the top row of a chess board, then the second row, third row, etc, then back to the beginning. Of course, this will be done in a setInterval so that each frame shows after a short delay.

If you vaguely understood that explanation, you should be able to piece together the following code:

[php lang=”JavaScript”]$(function () {
var canvas, context, image, width, height, xpos = 0, ypos = 0, index = 0, numFrames = 60, frameSize = 60;

image = new Image();
image.src = “spritesheet.png”;
image.onload = function() {
width = image.width;
height = image.height;
canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);

setInterval(function () {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(image, xpos, ypos, frameSize, frameSize, 0, 0, frameSize, frameSize);
xpos += frameSize;
index += 1;
if(index >= numFrames) {
xpos = 0;
ypos = 0;
index = 0;
}
else if(xpos + frameSize > width) {
xpos = 0;
ypos += frameSize;
}
}, 1000/24);
};
});[/php]

First we create and load the spritesheet image. When it’s loaded, we get the canvas, context, width and height of the image and start the interval.

In the interval function, we clear the canvas and draw the correct chunk of the source image to the canvas. We then have some not so elegant code to find the next rectangle to draw. I trust you’ll be able to work through all this. And the result:

http://www.bit-101.com/jscanvas/mar20.html

Flash animations converted to pure html5! Wallaby Schmallaby! 😉

This entry was posted in JavaScript. Bookmark the permalink.

4 Responses to JavaScript Day 20: SpriteSheets

  1. Tom says:

    This is great, I was wondering if it’d be possible to do an js version of an AS3 project I’m doing using blitting, now I think it is! Thanks, Tom

  2. Tonis says:

    Or just use a framework http://www.limejs.com/2011/02/21/introducing-sprite-sheets

    The implementation for canvas is almost exactly the same as here. For DOM we draw all frames once to different canvas and then switch the backgrounds. This makes the performance better if there are many instancase of same object on the screen.

    • keith says:

      Yes, of course you could just use a framework, but this would be a pretty short post if I just linked to some other site. 🙂 Personally, I find it far more interesting to figure out and explain how something is done than to just use code someone else has written.

  3. Phillip Kerman says:

    Quick note to help anyone else stepping through these… you don’t want to use spritesheet linked in your blog (it’s scaled differently):
    http://www.bit-101.com/blog/wp-content/uploads/2011/03/spritesheet-300×300.png

    …that would require different code (like the frameSize var to be like 37 or so)… you DO want to use:
    http://www.bit-101.com/jscanvas/spritesheet.png

Leave a Reply