using odd number of sprites in multi-row spriteSheet?

Using XNA it's pretty easier to loop through a sprite sheet, I tell it how many rows and how many columns it has and I have a method that loops through the whole set.

I usually use this method in my sprite class, but I have a sprite sheet that has a odd number of sprites, and does not use the entire last line. Any ideas on how to do this?

for example: I have 3 rows of 6 columns, but on the last row I only have 3 sprites.

Thanks!

You're telling it how many rows and columns it has. Simply also tell it how many sprites it has on it. Therefore allowing you to skip over the final sprites as you loop.

(I assume you know how to index rows and columns with / and %? If not then this will tell you.)

So for something like this:

const int rowCount = 3;
const int columnCount = 6;
for(int i = 0; i < rowCount * columnCount; ++i)
{
int row = i / columnCount;
int column = i % columnCount;
}


Simply change it to something like this:

const int rowCount = 3;
const int columnCount = 6;
const int spriteCount = 15;
for(int i = 0; i < spriteCount; ++i)
{
int row = i / columnCount;
int column = i % columnCount;
}


(And then, obviously, you're generating rectangles like this)

int width = texture.Width / columnCount;
int height = texture.Height / rowCount;
Rectangle sourceRectangle = new Rectangle(column * width, row * height, width, height);

• maybe I am not getting anything(or because I haven't tested yet) but assuming I have 75 by 75 sprites. 3 rows, 6 columns and 15 sprites in total (row 1:6 sprites row 2:6 row 3:3) I used your calculation above and my second sprite (row 0, column 1) my rectangle is 12,0,12,25...which doesnt seem to fit my 75x75 sprite Apr 14, 2011 at 18:57
• @FreshJays The values of width and height in my above code are the size of the sprite, derived from the size of the texture that the sprites are packed in. If you know the pixel size of your sprite, you can use that value directly and ignore the size of the texture. Apr 15, 2011 at 4:26

I haven't used XNA, but when I've used sprite sheets in the past, part of the meta data associated with that sprite sheet is the number of frames on it. Usually if that number is '0' I just compute it to be the width * height, but if it's non-zero I use that and assume that the last sprites are blank.

• +1 because if XNA does not support this then this is the type of functionality you would want to wrap around what they do do :) Mar 25, 2011 at 21:08

When you say you have a method that "loops through the whole set", do you mean it loops through the whole Spritesheet, or the whole current row? Normally when I make Spritesheets, I have every row being a single animation, and every column being a frame of that animation.

In my constructor, I set the maximum number of rows and columns my spritesheet can have (although that may not even be necessary). An animation won't necessarily have that many frames (e.g. rows per column) as the maximum, but it's good to keep track of.

Then, whenever you want to advance a frame of you're animation, simply have a method to do it where you pass the number of frames on the current row.

This is one way:

void AdvanceFrame()
{
//currentNumFrames is the number of frames in the current animation -- see below
frameIndex = (frameIndex + 1) % currentNumFrames;

srcRect = new Rectangle(frameIndex * frameWidth, animationIndex * frameHeight, frameWidth, frameHeight);
}


Then, whenever you want to animate, you would call a function like this:

public void Animate(int animation, int framesInAnimation)
{
//In your update you will animate when (!paused)
paused = false;

animationIndex = animation;
frameIndex = 0;
currentNumFrames = frameInAnimation;

//Same as before, you can put it in a method.
RealignSrcRectangle();
}


Another way is you could simply put the number of frames per row in an array. Then, you wouldn't need to send in framesInAnimation and store a currentNumFrames, in your advance you would do this instead:

    frameIndex = (frameIndex + 1) % framesPerAnimation[animationIndex];


I just implemented a animated sprite class that takes the total frames like others have said, and the frame size. I then calculate the rows and columns from those. Since we have large animations and didn't want to go over 2048x2048 sprite sheet size I also can span multiple sprite sheets.