Friday, August 12, 2011

Let's Make A Game! Episode 6: Sprite Strips: Not As Sexy As They Sound

Whew. This was a tough lesson for me.

I'm not really good at doing what people tell me to do. If you give me a list of things to accomplish, I'll usually miss one or two items on the list. It's just the way I am. I'm also not very good at dictation, which is what a lot of this stuff feels like. Add these two personality flaws, and you get a heap of trouble with this exceptionally long lesson. Let's dive in anyway.

This lesson deals with animations, like walking or jumping. There are two ways to handle animation in a 2-D game.

1) Each individual step that the character takes is its own separate picture played in quick succession. That means that for, say, Mario to take a step, you would have to do something like this:
Step 1: Load mariowalk1.jpg.
Step 2: Unload mariowalk1.jpg.
Step 3: Load mariowalk2.jpg.
Step 4: Unload mariowalk2.jpg.
Step 15: Unload mariowalk8.jpg.
Step 16: Load mariowalk1.jpg.
Now, you could do this easily by creating a variable called MarioWalk and then adding 1 to it every time it passes through a loop and play its corresponding picture. Then, when it reaches 8, you drop it back to 1.

However, think about it: Is this really the best use of processor cycles? Loading and unloading content isn't something that we want to waste too much time on. There has to be a better way.

2) Sprite strips. A sprite strip is a picture that already has all 8 still pictures in it. Therefore, you would do something like this:
Step 1: Load mariospritestrip.jpg.
Step 2: Create a rectangle with the first part of the image in it.
Step 3: Replace it with the second part of the image.
And so on. Math appears to be quicker for the processor than loading and unloading content, but I could be wrong about that. Either way, we're learning sprite strips and there is not a thing you can do about it.

So here's how it works. Every time we go through this loop, we're going to use a few variables.

The first two are ElapsedTime and FrameTime. We'll keep adding 1 to ElapsedTime until we reach the value that we've set for FrameTime. When that happens, we'll add 1 to CurrentFrame and reset ElapsedTime to 0. We'll keep doing this until CurrentFrame reaches the same amount as a different variable, frameCount. Then, we reset currentFrame back to 0 and start over.

Next, for every instance of currentFrame, we're going to look at the sprite strip. We'll multiply currentFrame by how wide the frame needs to be. For example, if the frame needs to be 10 pixels wide (which it doesn't, but we'll say it does for the sake of argument) and the currentFrame value is 3, we'll multiply the two to get a value of 30. Our formula then figures out that we need to grab the rectangle that starts from pixel 30 in the sprite strip and continues another 10 pixels. Then, once the currentFrame value changes, it'll start from pixel 40 and continue from there.

Clear as mud.