The XNA Tutorial
Appendix A – Sprite Sheets
Hello all, I’m back again to bestow more of my XNA knowledge upon you :-) Today, we’ll be taking a brief look at Sprite Sheets.
A What-Sheet?
Yeah, a sprite sheets. If you’re familiar with them already, then chances are you’ll want to jump straight ahead to the implementation and skip the introductions. If you’re not familiar then type “Spritesheet” into Google Images (followed by the name of your favourite SNES character if you like). You should see a number of images appear containing the same character in multiple poses. These are sprite sheets (occasionally called charsets or character sets) and when implemented correctly within a game, they become animated sprites.
Enough talking, it’s time to crack on with things. First of all we need a new Windows Game project so create a new project named SpritesheetTutorial (or whatever you want to call it) – a quick note, if you’re awesome and you’re already building a game you can probably just implement what follows straight in to your game.
Now, download the AppendixA-Resources.zip file attached to this post and unpack the image inside. Next, load the image into the Content folder of the project – this was covered in The XNA Tutorial – Part 1 so go back there and take a look if you don’t know how – and then create a new class file named SpriteSheet. Cool, we’re set up, time for the coding bit.
The Coding Bit
I’m not going to go through things step by step this time. Instead I’m providing you with the full source and a brief explanation. If you’re still confused by the end of this tutorial, download the attached sample project, named SpritesheetTutorial.zip, and open up the solution inside it. You’ll find that the Spritesheet class is heavily commented to help you understand the mechanics of the class better.
Right, first delete everything that’s in the SpriteSheet class file that you just made, and then add in the following:
[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] System;[/FONT]
[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] System.Collections.Generic;[/FONT]
[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] System.Linq;[/FONT]
[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] System.Text;[/FONT]
[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] Microsoft.Xna.Framework;[/FONT]
[COLOR=blue][FONT="]using[/FONT][/COLOR][FONT="] Microsoft.Xna.Framework.Graphics;[/FONT]
[FONT="] [/FONT]
[COLOR=blue][FONT="]namespace[/FONT][/COLOR][FONT="] SpritesheetTutorial[/FONT]
[FONT="]{[/FONT]
[FONT="] [COLOR=blue]class[/COLOR] [COLOR=#2B91AF]SpriteSheet[/COLOR][/FONT]
[FONT="] {[/FONT]
[FONT="] [COLOR=#2B91AF]Game1[/COLOR] GAME_REF;[/FONT]
[FONT="] [COLOR=#2B91AF]Texture2D[/COLOR] sheet;[/FONT]
[FONT="] [COLOR=#2B91AF]Vector2[/COLOR] position;[/FONT]
[FONT="] [COLOR=#2B91AF]Rectangle[/COLOR][,] sourceRects;[/FONT]
[FONT="] [COLOR=blue]int[/COLOR] currentCol, currentRow, intervalMs, counterMs;[/FONT]
[FONT="] [/FONT]
[FONT="] [COLOR=blue]public[/COLOR] SpriteSheet([COLOR=#2B91AF]Game1[/COLOR] g, [COLOR=blue]string[/COLOR] path, [COLOR=blue]int[/COLOR] w, [COLOR=blue]int[/COLOR] h, [COLOR=blue]int[/COLOR] cols, [COLOR=blue]int[/COLOR] rows, [COLOR=blue]int[/COLOR] interval)[/FONT]
[FONT="] {[/FONT]
[FONT="] GAME_REF = g;[/FONT]
[FONT="] sheet = g.Content.Load<[COLOR=#2B91AF]Texture2D[/COLOR]>(path);[/FONT]
[FONT="] position = [COLOR=#2B91AF]Vector2[/COLOR].Zero;[/FONT]
[FONT="] intervalMs = interval;[/FONT]
[FONT="] counterMs = currentCol = currentRow = 0;[/FONT]
[FONT="] [COLOR=green]//Create rectangles[/COLOR][/FONT]
[FONT="] sourceRects = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Rectangle[/COLOR][rows, cols];[/FONT]
[FONT="] [COLOR=blue]for[/COLOR] ([COLOR=blue]int[/COLOR] i = 0; i < rows; i++)[/FONT]
[FONT="] [COLOR=blue]for[/COLOR] ([COLOR=blue]int[/COLOR] j = 0; j < cols; j++)[/FONT]
[FONT="] sourceRects[i, j] = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]Rectangle[/COLOR](j * w, i * h, w, h);[/FONT]
[FONT="] }[/FONT]
[FONT="] [/FONT]
[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]void[/COLOR] Update([COLOR=#2B91AF]GameTime[/COLOR] gameTime)[/FONT]
[FONT="] {[/FONT]
[FONT="] [COLOR=blue]if[/COLOR] (counterMs >= intervalMs)[/FONT]
[FONT="] {[/FONT]
[FONT="] currentCol++;[/FONT]
[FONT="] [COLOR=blue]if[/COLOR] (currentCol == sourceRects.GetLength(1))[/FONT]
[FONT="] {[/FONT]
[FONT="] currentRow++;[/FONT]
[FONT="] currentCol = 0;[/FONT]
[FONT="] [COLOR=blue]if[/COLOR](currentRow == sourceRects.GetLength(0))[/FONT]
[FONT="] currentRow = 0;[/FONT]
[FONT="] }[/FONT]
[FONT="] [/FONT]
[FONT="] counterMs = 0;[/FONT]
[FONT="] }[/FONT]
[FONT="] [/FONT]
[FONT="] counterMs += gameTime.ElapsedGameTime.Milliseconds;[/FONT]
[FONT="] }[/FONT]
[FONT="] [/FONT]
[FONT="] [COLOR=blue]public[/COLOR] [COLOR=blue]void[/COLOR] Draw([COLOR=#2B91AF]GameTime[/COLOR] gameTime)[/FONT]
[FONT="] {[/FONT]
[FONT="] GAME_REF.sb.Begin([COLOR=#2B91AF]SpriteBlendMode[/COLOR].AlphaBlend);[/FONT]
[FONT="] GAME_REF.sb.Draw(sheet, position, sourceRects[currentRow, currentCol], [COLOR=#2B91AF]Color[/COLOR].White);[/FONT]
[FONT="] GAME_REF.sb.End();[/FONT]
[FONT="] }[/FONT]
[FONT="] }[/FONT]
[FONT="]}[/FONT]
Next go into the Game1 class and add the following members:
[FONT="] [COLOR=blue]public[/COLOR] [COLOR=#2B91AF]SpriteBatch[/COLOR] sb { [COLOR=blue]get[/COLOR] { [COLOR=blue]return[/COLOR] [COLOR=blue]this[/COLOR].spriteBatch; } }[/FONT]
[FONT="] [/FONT]
[FONT="] [COLOR=#2B91AF]SpriteSheet[/COLOR] sheet;[/FONT]
The second member doesn’t need explaining, and neither does the first if you were paying attention during Part 1 of this tutorial set. If you weren’t, basically, this is a property that provides access to the SpriteBatch other classes can draw from it.
Next, we need to add the following to the Initialize method:
[FONT="] sheet = [COLOR=blue]new[/COLOR] [COLOR=#2B91AF]SpriteSheet[/COLOR]([COLOR=blue]this[/COLOR], [COLOR=#A31515]"sheet"[/COLOR], 240, 296, 6, 5, 50);[/FONT]
Now here we’re giving our SpriteSheet a lot of information through parameters. The first parameter provides a reference to the Game1 class (as always); the second provides the name of the file we want to load through the ContentManager as our sprite. The third and fourth parameters represent the width and height of each frame in the sprite sheet. To work this out quickly without having to use any photo editors, just take the width of the entire image and divide it by the number of frames in a row – do the same for the height but divide by the number of frames in a column. The number of rows and columns are the fifth and sixth parameters, and finally, the seventh parameter is the speed at which we want frames to flip over, in milliseconds. Currently, I have it set to 50ms, which is around 20 frames a second, so feel free to change it so that it runs faster or slower.
Next we need to update and draw our sprite. First add the following to the Update method of the Game1 class:
[FONT="] sheet.Update(gameTime);[/FONT]
Then add the following to the Draw method:
[FONT="] sheet.Draw(gameTime);[/FONT]
That's All Folks
And that’s all there is! I’m sure you have many questions: What’s happening in the SpriteSheets Draw method? Why is there an array of rectangles called SourceRect? Why are we using a Vector2 for the sprites position? And so on...
A lot of the questions are answered in the source code, and a lot of them can be answered by just reading the code carefully and using your powers of deduction to work out what’s going on. And trust me you need to; how else are you going to extend the powers of the sprite sheet to your own projects?
For those of you who have already gotten to grips with what’s going on here are a few questions/exercises to consider:
1. What if the sprite sheet contains multiple poses for the same character?
2. What if the sprites aren’t aligned in columns rows?
3. What if we want to increase the speed of animation during the game?
4. What if we want to play the animation backwards to?
I’ll give you a clue for number 2: get a decent image editor ;-)
Until next time!
Edited by Roger, 28 January 2011 - 10:01 PM.


Sign In
Create Account


Back to top









