Free and easy Animation design in XNA

In my previous blog, I showed you how to use a pre-built class to generate animations that move like a Gif, mainly because I have not shown you how to move the image.  But reviewing the code, it seemed somewhat complicated, which means I didn’t quite get it, maybe you did.  So when that happens I “boil” it down to the absolute minimum.

(Previous blog: https://blogs.msdn.com/b/devschool/archive/2012/03/13/free-animated-sprites-software-reading-the-flipbook-image-and-showing-it.aspx)

So to deviate from the previous blog, I decided to show how to implement, simply, the process of showing the several images in a spritesheet.  And yes, I realize that there are sheets out there with a gazillion of images, I am talking about using very simple spritesheets that have a single row.

Let’s start with a spritesheet that looks like the following:

image

This was carefully made using Paint, just the plain old Paint that is included on Windows by default.  If you don’t get the squares exactly right, then you may not see the program working correctly. the following code the rectangles to contain the correct image are generated.  In production code you would use loops and collections to simplify the code.  The code sample attached to this blog contains all of the code and was working when I posted it.

Creating the rectangle to show the single frame to generate the sprite from a spritesheet:

  1. /**The FrameWidth variable is used to determine the size of the frame********/
  2.             int FrameWidth = myTexture.Width / 4;
  3.             /******************************************************************************/
  4.             /**Note: This is inefficient code, but demonstrates how to use rectangles******/
  5.             //The entire spritesheet
  6.             Rectangle RectAll = new Rectangle(FrameWidth , 0, FrameWidth, myTexture.Height);
  7.             /******************************************************************************/
  8.             //The first rectangle in the spritesheet
  9.             Rectangle Rect1 = new Rectangle(0, 0, FrameWidth, myTexture.Height);
  10.             /******************************************************************************/
  11.             //Second rectangle
  12.             Rectangle Rect2 = new Rectangle(FrameWidth, 0, FrameWidth, myTexture.Height);
  13.             /******************************************************************************/
  14.             //Third rectangle
  15.             Rectangle Rect3 = new Rectangle(FrameWidth*2, 0, FrameWidth, myTexture.Height);
  16.             /******************************************************************************/
  17.             //Fourth Rectangle
  18.             Rectangle Rect4 = new Rectangle(FrameWidth*3, 0, FrameWidth, myTexture.Height);
  19.             /******************************************************************************/

As you can see the lines of code move through the numbers in the image first using the Framewidth from the x location on the image of zero (not the playing field).  Then the location is moved to the x location at the Width of the frame, the 2X of the width of the frame and then 3X of the width of the frame.

So it looks like this:

  • X=0 times FrameWidth, this will yield the rectangle that shows the first frame
  • X=1 times FrameWidth, this will yield the rectangle that shows the second frame
  • X=2 times FrameWidth, this will yield the rectangle that shows the third frame
  • X=3 times FrameWidth, this will yield the rectangle that shows the fourth frame
  • And so forth, if you had more frames.

Seems repetitive?  That is one of the things computers are good at and humans aren’t.

Showing the Frame

In this case the spriteBatch.Draw does most of the work, you could create a class to simplify the “Game” class, but we won’t in this case to keep everything really simple.  You could also place the rectangle processing directly in the spriteBatch.Draw code, but I doubt if that would be efficient and it would be really messy.

  • In the first spriteBatch.Draw shows the whole spritesheet.
  • The next spriteBatch.Draw shows the last rectangle, in this case a 4 and it is at the same level as the full spritesheet, but shifted over the width of the full spritesheet with 30 pixels added to it.
  • Following that spriteBatch.Draw is the third rectangle, in this case it is a 3 and it is one frame down from the top of the previous block, so that is appears to be attached, it isn’t, but certainly looks like it.
  • The next two spriteBatch.Draw lines do frame 2 and frame 1 in that order with each one dropped down one rectangle.
  • Finally there is the spriteBatch.End(), which ends our efforts.

 

  1. /*** SpriteBatch processing*****************************************************/
  2.  spriteBatch.Begin();
  3.  /*******************************************************************************/
  4.  /** Here we draw the entire spritesheet ****************************************/
  5.  spriteBatch.Draw(myTexture, new Vector2(0,0), Color.Wheat);
  6.  /*******************************************************************************/
  7.  /**Now we implement the numbers on the same level as the entire spritesheet*****/
  8.  spriteBatch.Draw(myTexture, new Vector2(myTexture.Width+30, myTexture.Height * 0),
  9.      Rect4, Color.Wheat);
  10.  /********************************************************************************/
  11.  spriteBatch.Draw(myTexture, new Vector2(myTexture.Width + 30, myTexture.Height * 1),
  12.      Rect3, Color.Wheat);
  13.  /********************************************************************************/
  14.  spriteBatch.Draw(myTexture, new Vector2(myTexture.Width + 30, myTexture.Height * 2),
  15.      Rect2, Color.Wheat);
  16.  /********************************************************************************/
  17.  spriteBatch.Draw(myTexture, new Vector2(myTexture.Width + 30, myTexture.Height * 3),
  18.      Rect1, Color.Wheat);
  19.  /********************************************************************************/
  20.  spriteBatch.End();

What the output will look like:

image

 

The entire code looks like the following:

  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Graphics;
  3. using Microsoft.Xna.Framework.Input;
  4.  
  5. namespace AnimatedSprite
  6. {
  7.     /// <summary>
  8.     /// This is the main type for your game
  9.     /// </summary>
  10.     public class Game1 : Microsoft.Xna.Framework.Game
  11.     {
  12.         GraphicsDeviceManager graphics;
  13.         SpriteBatch spriteBatch;
  14.         /*********The following two variables were added by author***/
  15.         private Viewport viewport;
  16.         private Texture2D myTexture;
  17.         /************************************************************/
  18.         public Game1()
  19.         {
  20.             Content.RootDirectory = "Content";
  21.             graphics = new GraphicsDeviceManager(this);
  22.         }
  23.         protected override void Initialize()
  24.         {
  25.             base.Initialize();
  26.         }
  27.         protected override void LoadContent()
  28.         {
  29.             // Create a new SpriteBatch, which can be used to draw textures.
  30.             spriteBatch = new SpriteBatch(GraphicsDevice);
  31.           
  32.             /****************Added by author****************/
  33.             myTexture = Content.Load<Texture2D>("Numbers");
  34.             /****************Added by author****************/
  35.             viewport = graphics.GraphicsDevice.Viewport;
  36.             /***********************************************/
  37.         }
  38.         protected override void Update(GameTime gameTime)
  39.         {
  40.             // Allows the default game to exit on Xbox 360 and Windows.
  41.             if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
  42.                 this.Exit();
  43.             base.Update(gameTime);
  44.         }
  45.         protected override void Draw(GameTime gameTime)
  46.         {
  47.             graphics.GraphicsDevice.Clear(Color.Yellow);
  48.             /************Added by author ************************************************/
  49.             /**The FrameWidth variable is used to determine the size of the frame********/
  50.             int FrameWidth = myTexture.Width / 4;
  51.             /******************************************************************************/
  52.             /**Note: This is inefficient code, but demonstrates how to use rectangles******/
  53.             
  54.             /******************************************************************************/
  55.             //Rectangle will be used to show the first frame in the spritesheet
  56.             Rectangle Rect1 = new Rectangle(0, 0, FrameWidth, myTexture.Height);
  57.             /******************************************************************************/
  58.             //Rectangle will be used to show the second frame
  59.             Rectangle Rect2 = new Rectangle(FrameWidth, 0, FrameWidth, myTexture.Height);
  60.             /******************************************************************************/
  61.             //Rectangle will be used to show the third frame
  62.             Rectangle Rect3 = new Rectangle(FrameWidth*2, 0, FrameWidth, myTexture.Height);
  63.             /******************************************************************************/
  64.             //Rectangle will be used to show the fourth frame
  65.             Rectangle Rect4 = new Rectangle(FrameWidth*3, 0, FrameWidth, myTexture.Height);
  66.             /******************************************************************************/
  67.             /*** SpriteBatch processing*****************************************************/
  68.             spriteBatch.Begin();
  69.             /*******************************************************************************/
  70.             /** Here we draw the entire spritesheet ****************************************/
  71.             spriteBatch.Draw(myTexture, new Vector2(0,0), Color.Wheat);
  72.             /*******************************************************************************/
  73.             /**Now we implement the numbers on the same level as the entire spritesheet*****/
  74.             spriteBatch.Draw(myTexture, new Vector2(myTexture.Width+30, myTexture.Height * 0),
  75.                 Rect4, Color.Wheat);
  76.             /********************************************************************************/
  77.             spriteBatch.Draw(myTexture, new Vector2(myTexture.Width + 30, myTexture.Height * 1),
  78.                 Rect3, Color.Wheat);
  79.             /********************************************************************************/
  80.             spriteBatch.Draw(myTexture, new Vector2(myTexture.Width + 30, myTexture.Height * 2),
  81.                 Rect2, Color.Wheat);
  82.             /********************************************************************************/
  83.             spriteBatch.Draw(myTexture, new Vector2(myTexture.Width + 30, myTexture.Height * 3),
  84.                 Rect1, Color.Wheat);
  85.             /********************************************************************************/
  86.             spriteBatch.End();
  87.  
  88.             base.Draw(gameTime);
  89.         }   
  90.     }
  91. }

SimpleSpriteSheets1.zip