Bill Reiss is a Windows Platform Development MVP and a Senior Consultant for AgileThought

Intro To XNA on Windows Phone Part 2

In the last post we created a new XNA game solution for Windows Phone, added an image to draw to the content project, loaded it, and drew it to the screen. We also explored how to remove the taskbar and taking advantage of hardware scaling for performance. At the end of Part 1 we were somewhere around here:

image

Here is the source code for the starting point for this post:

http://www.billreiss.com/wp-content/uploads/2012/04/MyFirstGame_part1_completed.zip

Now let’s take it a step further and only draw a part of the image so that we only see one frame at a time.

This image that we’re drawing (called a texture in XNA) is known as a sprite sheet and it’s copied from the Platformer sample that ships with XNA. A sprite sheet is an image that contains multiple frames of motion for a sprite or sprites.

When using the graphics processor (GPU) to draw like XNA does, it’s more efficient to use a single texture and draw only what you need from it instead of loading a texture for each frame and swapping them. It’s even more efficient to pack all of your textures into a single texture and with each draw call draw only what you need. This is because there is significant overhead in telling the graphics processor to use a different texture.

The sprite sheet that we’re using is the texture used when the character is running. There is one part of the texture for each frame in the running animation and by drawing these in sequence we can get the illusion that the character is running.

TIP: If creating your own character, you can draw over an existing sprite sheet, it’s easy to find these on the internet. By drawing over an existing one it’s easier to draw the character in the correct positions. Instead of figuring out what positions you need to give the illusion of running you can just focus on the artwork.

To draw only a single frame, let’s add fields to store the current frame and the frame height and width:

int playerCurrentFrame = 0;
int runFrameWidth = 0;
int runFrameHeight = 0;

In the LoadContent method we’ll take the loaded player texture and calculate the frame width and height from it:

player = Content.Load<Texture2D>("run");
runFrameWidth = player.Width / 10;
runFrameHeight = player.Height;

Then in the Draw method, we’ll change the Draw call as follows:

spriteBatch.Draw(player, new Vector2(80, 300),
    new Rectangle(playerCurrentFrame * runFrameWidth, 0,
    runFrameWidth, runFrameHeight), Color.White);

This is a different overload of the Draw method, there are a lot of them. Take some time to look at all of the different SpriteBatch Draw calls since the right overload can save you a lot of effort.

Run the app again. Now you should only see one frame.

image

Now if we want to animate the character, we can do this with the Update method.

playerCurrentFrame++;
playerCurrentFrame = playerCurrentFrame % 10;

Since there are 10 frames in this animation, the frame count is incremented every time the Update method is called, and when it gets to 10 it starts over. Run the app again.

Looks like he’s running a little fast, so let’s slow him down a bit. Instead of updating the current frame every time Update is called, it’s do it based on a time value. Add the following fields to the Game class:

double playerAnimationDelay = .05;
double currentPlayerAnimationDelay = 0;

And in the Update method, the code changes as follows:

currentPlayerAnimationDelay += gameTime.ElapsedGameTime.TotalSeconds;
while (currentPlayerAnimationDelay > playerAnimationDelay)
{
    playerCurrentFrame++;
    playerCurrentFrame = playerCurrentFrame % 10;
    currentPlayerAnimationDelay -= playerAnimationDelay;
}

Now by changing the playerAnimationDelay value you can control exactly how fast your character animates. He’s also facing the wrong way for our needs, so change the spriteBatch Draw call as follows:

spriteBatch.Draw(player, new Vector2(80, 300),
    new Rectangle(playerCurrentFrame * runFrameWidth, 0,
    runFrameWidth, runFrameHeight),
    Color.White, 0, Vector2.Zero, 1, SpriteEffects.FlipHorizontally, 0);

Cool now he should be facing the right way and running at a slower speed.

image

http://www.billreiss.com/wp-content/uploads/2012/04/MyFirstGame_part2_completed.zip

In the next post we’ll look at giving our character something to run on.