Article : Simple 2D Animated Sprite
In this part, we are going to make the animations come from a single bitmap image, or a "sprite sheet". The first thing to do is create a new image and then copy each of the individual images into it, spacing them out accordingly. I have done this already, so you can just download my copy to go along with this article.
Add this new image file to the project. Next we are going to edit the private variables we have in Game1.cs. Instead of the List of scribbles, we will have just a single Texture2D variable. Since we are using a single texture now, we will need to store the rectangles of the scribbles on the new big texture. For this we will assign a variable to hold each of those. So the new private variable decelerations in Game1.cs should look like the following:
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
private Texture2D scribbles; // a texture that holds all the animated tiles in a sheet
private List rectagles; // list of rectangles for the scribbles
private Vector2 scribbleOrigin; // the center of the sprite
private Vector2 scribblePos; // where to draw the sprite
private int frameCount; // how many frames are there to animate
private float timePerFrame; // how long to display each frame
private float totalElapsed; // how long has it elapsed.
private int currentFrame; // what frame are we on
private int framesPerSec; // how many frames of animation do we want to show per second.
...
Next we need to change how we load the content. Instead of loading all the tiles into their own texture2d object, we are just loading up the sprite sheet into its own, then making a list of rectangles of where each of the individual frames are at. Your LoadContent() should look like the following:
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
scribbles = Content.Load("scribbles");
rectagles = new List();
// add each of the frames to the list of rectangles (could use a for loop, but for
// ease of showing, I listed them out individually.
rectagles.Add(new Rectangle(0, 0, 128, 128));
rectagles.Add(new Rectangle(128, 0, 128, 128));
rectagles.Add(new Rectangle(256, 0, 128, 128));
rectagles.Add(new Rectangle(384, 0, 128, 128));
rectagles.Add(new Rectangle(0, 128, 128, 128));
rectagles.Add(new Rectangle(128, 128, 128, 128));
rectagles.Add(new Rectangle(256, 128, 128, 128));
rectagles.Add(new Rectangle(384, 128, 128, 128));
rectagles.Add(new Rectangle(0, 256, 128, 128));
rectagles.Add(new Rectangle(128, 256, 128, 128));
frameCount = 10;
framesPerSec = 15;
timePerFrame = (float) 1/framesPerSec;
currentFrame = 0;
totalElapsed = 0;
scribbleOrigin = new Vector2(128 / 2, 128 / 2);
scribblePos = new Vector2(graphics.PreferredBackBufferWidth/2, graphics.PreferredBackBufferHeight/2);
}
Now the last thing to do is to change our Draw function to handle one texture, and use a source rectangle to grab just a portion of the main texture. All we need to do is change the Draw parameters of the spriteBatch object to the following:
spriteBatch.Draw(scribbles, scribblePos, rectagles[currentFrame], Color.White, 0, scribbleOrigin, 1.0f, SpriteEffects.None, 0.6f);
Now you should be able to compile and run and see the nice animation once again, but this time, it is just using 1 texture which is much more efficient.
This finishes up this part of the article on simple animations. The next page we will continue on with this and refactor the code into its own class. To download the completed project that we have so far, click here.

August 8th, 2010 - 09:22
Very nice. With a few modifications I was able to use your class to animate character movement as well as regular animation. Before this I was having a lot of trouble understanding animation in C# and XNA. Thanks and keep up the great work.