App Hub
Banner of Game Development Tutorial

animating the player

Animate the player ship

 

We now have a ship that we can move around the screen, but without any animation, it doesn’t look very good. We can fix that by building a simple animation system.

As demonstrated in the video, animation in 2D games is easily accomplished by playing a set of images that are slightly different from one another very quickly; similar to how the position changes in the last step gave the illusion of motion.

In our game project, we have a sprite sheet that includes eight frames of animation for our player ship. We’ll cycle through these frames continuously throughout the game to make the ship animate. The first thing we’ll need to do is create a class called Animation.cs.

Add a new class to your project by pressing SHIFT + ALT + C, and typing in the name Animation.cs. Press ENTER.

inside animation.cs

We’re inside our new Animation.cs code file. The first thing to do is replace a few lines at the very top. Delete all the using statements at the top, and replace them with the following lines:

// Animation.cs
//Using declarations
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

And, similar to the Player class we created a few steps ago, we’re going to add all the data and the methods we’ll need to make this class work.

Place your cursor just after the { mark inside the Animation class. Add a new line and add the following lines:

// The image representing the collection of images used for animation
Texture2D spriteStrip;

// The scale used to display the sprite strip
float scale;

// The time since we last updated the frame
int elapsedTime;

// The time we display a frame until the next one
int frameTime;

// The number of frames that the animation contains
int frameCount;

// The index of the current frame we are displaying
int currentFrame;

// The color of the frame we will be displaying
Color color;

// The area of the image strip we want to display
Rectangle sourceRect = new Rectangle();

// The area where we want to display the image strip in the game
Rectangle destinationRect = new Rectangle();

// Width of a given frame
public int FrameWidth;

// Height of a given frame
public int FrameHeight;

// The state of the Animation
public bool Active;

// Determines if the animation will keep playing or deactivate after one run
public bool Looping;

// Width of a given frame
public Vector2 Position;

public void Initialize()
{
}
public void Update()
{
}
public void Draw()
{
}

You’ll notice, much like the Player class, we have an Initialize(), Update(), and Draw() method; animations need all three to be able to work right. Let’s start by filling out the Initialize() method. We’ll add some parameters that we can pass in each time we create a new animation, and then we’ll store the parameters to control the animation.

Replace the Initialize() method you just filled in with this version:

public void Initialize(Texture2D texture, Vector2 position,
int frameWidth, int frameHeight, int frameCount,
int frametime, Color color, float scale, bool looping)
{
// Keep a local copy of the values passed in
this.color = color;
this.FrameWidth = frameWidth;
this.FrameHeight = frameHeight;
this.frameCount = frameCount;
this.frameTime = frametime;
this.scale = scale;

Looping = looping;
Position = position;
spriteStrip = texture;

// Set the time to zero
elapsedTime = 0;
currentFrame = 0;

// Set the Animation to active by default
Active = true;
}

Like in the earlier steps, when we initialize a class object, we generally assign the object’s variables to copies of the values that are coming in from the parameters. This will come in very handy as we use this Animation class more and more – you can call Initialize() once for every object you want to use animation with different graphics, timings, and sizes, and each Animation object can then run on its own using the data you’ve passed in. You can have an animation for every object in your game!

Now, let’s fill in the Update() method. Like the Update() methods in the Game1 class, this method operates on GameTime – we’ll use this method to do the heavy lifting to decide whether or not enough time has passed in the animation to switch it to the next frame, and do the calculation to turn the frame count into the actual pixels we want to draw on the screen.

Replace the Update() method you just filled in above with this version:

public void Update(GameTime gameTime)
{
// Do not update the game if we are not active
if (Active == false)
return;

// Update the elapsed time
elapsedTime += (int)gameTime.ElapsedGameTime.TotalMilliseconds;

// If the elapsed time is larger than the frame time
// we need to switch frames
if (elapsedTime > frameTime)
{
// Move to the next frame
currentFrame++;

// If the currentFrame is equal to frameCount reset currentFrame to zero
if (currentFrame == frameCount)
{
currentFrame = 0;
// If we are not looping deactivate the animation
if (Looping == false)
Active = false;
}

// Reset the elapsed time to zero
elapsedTime = 0;
}

// Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
sourceRect = new Rectangle(currentFrame * FrameWidth, 0, FrameWidth, FrameHeight);

// Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
destinationRect = new Rectangle((int)Position.X - (int)(FrameWidth * scale) / 2,
(int)Position.Y - (int)(FrameHeight * scale) / 2,
(int)(FrameWidth * scale),
(int)(FrameHeight * scale));
}

All of the information about which pixels of the sprite sheet need to be drawn is stored in the sourceRect and destinationRect objects. This is what the Draw() method will consume to draw the right frame to the screen. Let’s complete the Draw() method and our work in this class will be done.

Replace the Draw() method you just filled in above with this version:

// Draw the Animation Strip
public void Draw(SpriteBatch spriteBatch)
{
// Only draw the animation when we are active
if (Active)
{
spriteBatch.Draw(spriteStrip, destinationRect, sourceRect, color);
}
}

That’s it for the Animation class. Now, any object we want to draw on the screen can be animated using this class. For now, there’s only one class that we’d want to do that with – that’s the Player class. Right now, it is using a simple Texture2D to represent itself graphically on screen. Let’s use this Animation class instead and give it a bit of motion.

Switch to the Player class by double-clicking the Player.cs file in the Solution Explorer in Visual Studio.

inside Player.cs

Now that we’re inside the Player class, let’s start by replacing the boring Texture2D that was the player’s graphic with our new Animation class.

Near the top of the Player.cs file, just after the first { mark after the Player class begins, replace the public Texture2D PlayerTexture; line with the following:

// Animation representing the player
public Animation PlayerAnimation;

Now that we’ve removed the old Texture2D, there are a number of methods that won’t work if we tried to build and run right now. We need to go change them, starting with the Initialize() method.

Scan down the Player.cs file and find the Initialize() method. Replace it with the following:

// Initialize the player
public void Initialize(Animation animation, Vector2 position)
{
PlayerAnimation = animation;

// Set the starting position of the player around the middle of the screen and to the back
Position = position;

// Set the player to be active
Active = true;

// Set the player health
Health = 100;
}

We also have two properties that are relying on the old texture data. We need to change them.

Find the Width and Height properties in the Player class, and replace them with the following:

// Get the width of the player ship
public int Width
{
get { return PlayerAnimation.FrameWidth; }
}

// Get the height of the player ship
public int Height
{
get { return PlayerAnimation.FrameHeight; }
}

Only Draw() and Update() are left. Let’s fix Draw().

Find the Draw() method and replace it with the following:

// Draw the player
public void Draw(SpriteBatch spriteBatch)
{
PlayerAnimation.Draw(spriteBatch);
}

Finally, find the Update() method in the Player class and replace it with the following:

// Update the player animation
public void Update(GameTime gameTime)
{
PlayerAnimation.Position = Position;
PlayerAnimation.Update(gameTime);
}

That’s it for the Player class. All the old static Texture2D drawing is gone, and the class now relies entirely on the Animation class to draw itself on the screen. We now have to link up two more items inside the Game1 class to make this change work in-game.

Switch to the Game1 class by double-clicking the Game1.cs file in the Solution Explorer in Visual Studio.

inside Game1.cs

The only step left is to tell the game to create the Animation and Initialize it with a sprite strip graphical file. The appropriate place to do this is in the LoadContent() method, where we were previously loading the static texture.

Find the LoadContent() method. Find the line marked player.Initialize(Content.Load<Texture2D>("player"), playerPosition); and replace it with the following:

// Load the player resources
Animation playerAnimation = new Animation();
Texture2D playerTexture = Content.Load<Texture2D>("shipAnimation");
playerAnimation.Initialize(playerTexture, Vector2.Zero, 115, 69, 8, 30, Color.White, 1f, true);

Vector2 playerPosition = new Vector2 (GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y
+ GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
player.Initialize(playerAnimation, playerPosition);

And finally, we need to pass the timing from the game loop’s Update() method into the Player class, so its Update() method can pass that onto the Animation class. Passing values up and down the chain of objects we own will soon become second nature. To do this, we’ll put a line in the UpdatePlayer() method we wrote a while back.

Find the UpdatePlayer() method. At the top of the method, add the following line:

player.Update(gameTime);

Now let’s compile with CTRL+F5 and take a look at our work.

You should still be able to move the ship around just as in the previous step, but now, you should see some fluttering effects from the sails and steam from the back of the ship. It’s animating!

If you have errors, try digging into them a bit to see if you can fix them yourself. You can easily double-click an error in the error list to automatically scroll to the location of the error. When you’re ready to move on, we’ll explore parallaxing backgrounds.

Move on to the next step: Drawing the Background

var gDomain='m.webtrends.com'; var gDcsId='dcschd84w10000w4lw9hcqmsz_8n3x'; var gTrackEvents=1; var gFpc='WT_FPC'; /*<\/scr"+"ipt>");} /*]]>*/
DCSIMG