# Getting Sprites from a SpriteSheet with Rows and Columns

I am having trouble reading a spritesheet with rows and columns. If it is just one row, then my code works fine. The sheet looks like this:

Right now, it only works with the first row. I can't figure out how to move it down to the next row. I know I have to change my SourceRect for the x and y but don't know to what.

Here's my code:

class SpriteSheet
{
public Texture2D Texture { get; set; }
public Vector2 Origin { get; set; }
public Rectangle SourceRect { get; set; }
public Vector2 position;

private float timer, interval;
private int currentFrame;
private int spriteWidth, spriteHeight, spriteSpeed;
private int rows, columns;
private KeyboardState currentKBState, previousKBState;

public SpriteSheet(Texture2D texture, int spriteWidth, int spriteHeight, int rows = 1, int columns = 0, int currentFrame = 1)
{
Texture = texture;
this.currentFrame = currentFrame;
this.spriteWidth = spriteWidth;
this.spriteHeight = spriteHeight;
this.rows = rows;
this.columns = columns;

spriteSpeed = 100;
interval = 200;
}

// Handle movement of sprite
public void Update(GameTime gameTime)
{
previousKBState = currentKBState;
currentKBState = Keyboard.GetState();

// Get the sprite from the sheet
// THIS LINE NEEDS TO BE CHANGED I THINK
SourceRect = new Rectangle(currentFrame * spriteWidth, 0, spriteWidth, spriteHeight);

if(currentKBState.GetPressedKeys().Length == 0)
{
if (currentFrame > 0 && currentFrame < 9)
currentFrame = 0;

if (currentFrame > 9 && currentFrame < 18)
currentFrame = 9;

if (currentFrame > 18 && currentFrame < 27)
currentFrame = 18;

if (currentFrame > 27 && currentFrame < 36)
currentFrame = 27;
}

// Animate Up
if (currentKBState.IsKeyDown(Keys.Up))
{
AnimateUp(gameTime);

// Check boundary
if (position.Y > 25)
position.Y -= (float) (spriteSpeed * gameTime.ElapsedGameTime.TotalSeconds);
}
}

private void AnimateUp(GameTime gameTime)
{
if (currentKBState != previousKBState)
currentFrame = 1;

timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

if(timer > interval)
{
currentFrame++;
if (currentFrame > 8)
currentFrame = 0;

timer = 0f;
}
}
}

• You keep Y at a constant 0. That parameter should (judging by the spritesheet) be set to a value corresponding to the direction your character is moving. Aug 7 '16 at 6:44

Your y-coordinate is always 0, so only the first row is used. You need to change this line:

SourceRect = new Rectangle(currentFrame * spriteWidth, 0, spriteWidth, spriteHeight);


into something like this (see the second parameter):

SourceRect = new Rectangle(currentFrame * spriteWidth, wantedRow * spriteHeight, spriteWidth, spriteHeight);

• Thanks for the reply; unfortunately, the sprite doesn't show up no matter what row I put for wantedRow. I did figure it out in another way but had to change some of the code.
– o.o
Aug 7 '16 at 18:03

So I changed up the code a bit to make it work:

Constructor change:

public SpriteSheet(Texture2D texture, int rows = 1, int columns = 0, int currentFrame = 0)
{
this.texture = texture;
this.sheetRows = rows;
this.sheetColumns = columns;

// Default = top left
this.currentFrame = currentFrame;

// Get a single sprite's width and height
sheetWidth = texture.Width / sheetColumns;
sheetHeight = texture.Height / sheetRows;
}


I noticed I didn't have to manually supply the width and height of the sprite and I could just get it from the sprite sheet. I handle the spriteSpeed and interval in my movement methods instead of the constructor now.

I removed the SourceRect line from the Update method and moved it to a custom Draw method:

public void Draw(SpriteBatch spriteBatch)
{
// Get the correct frame
spriteRow = currentFrame / sheetColumns;
spriteColumn = currentFrame % sheetColumns;

sourceRect = new Rectangle(sheetWidth * spriteColumn, sheetHeight * spriteRow, sheetWidth, sheetHeight);
origin = new Vector2(sourceRect.Width / 2, sourceRect.Height / 2);

spriteBatch.Draw(texture: texture, sourceRectangle: sourceRect, position: position, origin: origin, scale: new Vector2(1.0f));
}


Finally, getting the row and column of the sprite became easier with a little division.

If I wanted row 3 and column 1, the currentFrame would be 18. Knowing this, it was pretty straightforward to fix the part of the code where I reset the currentFrame where no keys are pressed.