Day 11 – Animating with sprite sheets

The holidays are over and we’re all back at the office getting back to the regular routine and feeling a bit like robots. No? OK, that’s maybe a stretch. Hopefully you at least like robots though, because we’re about to animate a little robot heart using sprite sheets twice: one using canvas and one using a div.

Animating with a sprite sheet is like moving a connected series of images past a set viewing area. Think of a viewmaster or a film strip if you’re old enough.

The image below shows you approximately what’s going on behind the scenes. We have one big image that contains every frame of the robot animation (the sprite sheet) and we display one at a time, moving along and down our list of images as we progress through the animation. Do this fast enough and you have animation :)

The sprite sheet

We’ll be using the same sprite sheet image (this one) for both variations. I won’t get into how to create a sprite sheet here, but there are a number of ways to make them and you certainly don’t have to put them together all by hand. I’ve used Keith Peter’s SWFSheet to export the sprite sheet I’m using here from a SWF.

First up, the canvas version

Once we’ve done our initial file set up, the first thing to do is load in our sprite sheet image. When we know our image has loaded, we set an interval to call our loop function 30 times a second, which is where everything happens.

	//load the image
	image = new Image();
	image.src = "robot2.png";
 
	image.onload = function() {
            //we're ready for the loop
            setInterval(loop, 1000 / 30);
        }

Great! we’re ready to actually make something happen. The loop function starts out easily enough with a call to clearRect(…) to clear our canvas. But what’s with that excessively long drawImage(…) function? It’s a bit ugly.

c.drawImage(image, xpos, ypos, frameSize, frameSize, 0, 0, frameSize, frameSize);

All those extra arguments are there because we are defining two different rectangles The first rectangle (xpos, ypos, frameSize, frameSize) defines the rectangle in our source image that we want to copy from. This will change every frame because we are updating the xpos and ypos values each time. The second rectangle (0, 0, frameSize, frameSize) defines where in our canvas we are drawing to. For this example that will never change. (You might also notice that both my width and height are being set to frameSize. To keep things simple, I’m using a square image area.)

Next up, we do a little bit of math to figure out exactly which part of our sprite sheet we should draw from to display the correct frame:

//each time around we add the frame size to our xpos, moving along the source image
xpos += frameSize;
//increase the index so we know which frame of our animation we are currently on
index += 1;
 
//if our index is higher than our total number of frames, we're at the end and better start over
if (index >= numFrames) {
	xpos =0;
	ypos =0;
	index=0;	
//if we've gotten to the limit of our source image's width, we need to move down one row of frames				
} else if (xpos + frameSize > image.width){
	xpos =0;
	ypos += frameSize;
}

We add our frameSize to our xpos to move along our sprite sheet horizontally (remember, our images our square). We also increment an index counter to keep track of what frame we’re on. If our index is higher than the total number of frames we have, it’s time to start over. If our next horizontal move would have us going past the width of our sprite sheet, we move down to the next row. This repeats over and over, creating our animation. Play with it here on JSFiddle.

One down!

Once more, with divs

I think you’re getting the hang of it now, so I’ll do a little less explaining for this one. We’re going to do pretty much the exact same thing except this time we’re calculating how to move the background image of a div so that the correct frame in the animation is visible.

The first notable difference is in our small block of CSS:

#anim {
	width:200px;
	height:200px;
	background-image: url(robot2.png);
}

We’re identifying our target div anim, setting its height and width (our viewable area), and assigning its background image (our sprite sheet).

Our loop function looks incredibly similar, or you might even say nicer since it doesn’t have nearly as many lines of comments. The only real difference is the first line:

div.style.backgroundPosition = (-xpos)+"px "+(-ypos)+"px";

We’re repositioning #anim‘s background image every frame. The calculations to determine the xpos and ypos values are the same as in the canvas version so the rest of the function should look very familiar. But you can see we’re using -xpos and -ypos – this is because we want to move the background image up and to the left to reveal the next frame.

So there you have it, the same sprite sheet animation two ways! Hopefully it was even a bit fun :)

And with that, we wrap up Day 11 of the 12 days of CreativeJS. Only one more to go!