How to: Animate a Sprite
This article demonstrates how to animate a sprite from a texture using a custom class.
The source code in this example presumes that the texture being loaded is a strip of equal-sized images. In this example, the texture provided is a 256×64 texture with 4 frames.
To draw an animated sprite
Follow steps 1–3 of How to: Draw a Sprite.
In your game's constructor, create an instance of the AnimatedTexture class.
private AnimatedTexture SpriteTexture;
public Game1() { ... SpriteTexture = new AnimatedTexture(Vector2.Zero, 0, 2.0f, 0.5f); }
Load the texture or textures that provide the image data for the animation. In this example, the AnimatedTexture class loads a single texture and divides it into frames of animation. It uses the last parameter to determine how many frames to draw each second. In this case, it draws 4 frames at 2 fps (frames per second).
private Viewport viewport;
private Vector2 shipPos; private SpriteBatch ForegroundBatch; protected override void LoadGraphicsContent( bool loadAllContent ) { if (loadAllContent) { // TODO: Load any ResourceManagementMode.Automatic content. ForegroundBatch = new SpriteBatch( graphics.GraphicsDevice );
// "ship" is the name of the sprite asset in the project.
SpriteTexture.Load( graphics.GraphicsDevice, content, "ship", 4, 2 );
viewport = graphics.GraphicsDevice.Viewport;
shipPos = new Vector2( viewport.Width / 2, viewport.Height / 2 );
}
// TODO: Load any ResourceManagementMode.Manual content.
}
In your game's Update method, determine which frame of animation to display.
protected override void Update( GameTime gameTime )
{ ...
// TODO: Add your update logic here.
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
// TODO: Add your game logic here.
SpriteTexture.UpdateFrame( elapsed );
base.Update( gameTime );
}
This is handled by AnimatedTexture's **UpdateFrame** method, which takes the elapsed seconds between updates as a parameter.
<pre IsFakePre="true" xmlns="http://www.w3.org/1999/xhtml">// class AnimatedTexture
public void UpdateFrame( float elapsed ) { if (Paused) return; TotalElapsed += elapsed; if (TotalElapsed > TimePerFrame) { Frame++; // Keep the Frame between 0 and the total frames, minus one. Frame = Frame % framecount; TotalElapsed -= TimePerFrame; } }
In your game's Draw method, call Draw on the AnimatedTexture object.
protected override void Draw( GameTime gameTime )
{ graphics.GraphicsDevice.Clear( Color.Black );
// TODO: Add your drawing code here.
ForegroundBatch.Begin();
SpriteTexture.DrawFrame( ForegroundBatch, shipPos );
ForegroundBatch.End();
base.Draw( gameTime );
}
**AnimatedTexture** will draw the sprite using the subrectangle of the texture that contains the desired animation.
<pre IsFakePre="true" xmlns="http://www.w3.org/1999/xhtml">// class AnimatedTexture
public void DrawFrame( SpriteBatch Batch, Vector2 screenpos ) { DrawFrame( Batch, Frame, screenpos ); } public void DrawFrame( SpriteBatch Batch, int Frame, Vector2 screenpos ) { int FrameWidth = myTexture.Width / framecount; Rectangle sourcerect = new Rectangle( FrameWidth * Frame, 0, FrameWidth, myTexture.Height ); Batch.Draw( myTexture, screenpos, sourcerect, Color.White, Rotation, Origin, Scale, SpriteEffects.None, Depth ); }
The Complete Example
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
ContentManager content;
private AnimatedTexture SpriteTexture;
public Game1()
{
graphics = new GraphicsDeviceManager( this );
content = new ContentManager( Services );
SpriteTexture = new AnimatedTexture(Vector2.Zero, 0, 2.0f, 0.5f);
}
protected override void Initialize()
{
// TODO: Add your initialization logic here.
base.Initialize();
}
private Viewport viewport;
private Vector2 shipPos;
private SpriteBatch ForegroundBatch;
protected override void LoadGraphicsContent( bool loadAllContent )
{
if (loadAllContent)
{
// TODO: Load any ResourceManagementMode.Automatic content.
ForegroundBatch = new SpriteBatch( graphics.GraphicsDevice );
// "ship" is the name of the sprite asset in the project.
SpriteTexture.Load( graphics.GraphicsDevice, content, "ship", 4, 2 );
viewport = graphics.GraphicsDevice.Viewport;
shipPos = new Vector2( viewport.Width / 2, viewport.Height / 2 );
}
// TODO: Load any ResourceManagementMode.Manual content.
}
protected override void UnloadGraphicsContent( bool unloadAllContent )
{
if (unloadAllContent == true)
{
content.Unload();
}
}
protected override void Update( GameTime gameTime )
{
// Allows the default game to exit on Xbox 360 and Windows.
if (GamePad.GetState( PlayerIndex.One ).Buttons.Back == ButtonState.Pressed)
this.Exit();
// Pauses and plays the animation.
if (GamePad.GetState( PlayerIndex.One ).Buttons.Start == ButtonState.Pressed)
{
if (SpriteTexture.IsPaused)
SpriteTexture.Play();
else
SpriteTexture.Pause();
}
// TODO: Add your update logic here.
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
// TODO: Add your game logic here.
SpriteTexture.UpdateFrame( elapsed );
base.Update( gameTime );
}
protected override void Draw( GameTime gameTime )
{
graphics.GraphicsDevice.Clear( Color.Black );
// TODO: Add your drawing code here.
ForegroundBatch.Begin();
SpriteTexture.DrawFrame( ForegroundBatch, shipPos );
ForegroundBatch.End();
base.Draw( gameTime );
}
}
public class AnimatedTexture
{
private int framecount;
private Texture2D myTexture;
private float TimePerFrame;
private int Frame;
private float TotalElapsed;
private bool Paused;
public float Rotation, Scale, Depth;
public Vector2 Origin;
public AnimatedTexture( Vector2 Origin, float Rotation, float Scale, float Depth )
{
this.Origin = Origin;
this.Rotation = Rotation;
this.Scale = Scale;
this.Depth = Depth;
}
public void Load( GraphicsDevice device, ContentManager content, string asset, int FrameCount, int FramesPerSec )
{
framecount = FrameCount;
myTexture = content.Load<Texture2D>( asset );
TimePerFrame = (float)1 / FramesPerSec;
Frame = 0;
TotalElapsed = 0;
Paused = false;
}
// class AnimatedTexture
public void UpdateFrame( float elapsed )
{
if (Paused)
return;
TotalElapsed += elapsed;
if (TotalElapsed > TimePerFrame)
{
Frame++;
// Keep the Frame between 0 and the total frames, minus one.
Frame = Frame % framecount;
TotalElapsed -= TimePerFrame;
}
}
// class AnimatedTexture
public void DrawFrame( SpriteBatch Batch, Vector2 screenpos )
{
DrawFrame( Batch, Frame, screenpos );
}
public void DrawFrame( SpriteBatch Batch, int Frame, Vector2 screenpos )
{
int FrameWidth = myTexture.Width / framecount;
Rectangle sourcerect = new Rectangle( FrameWidth * Frame, 0,
FrameWidth, myTexture.Height );
Batch.Draw( myTexture, screenpos, sourcerect, Color.White,
Rotation, Origin, Scale, SpriteEffects.None, Depth );
}
public bool IsPaused
{
get { return Paused; }
}
public void Reset()
{
Frame = 0;
TotalElapsed = 0f;
}
public void Stop()
{
Pause();
Reset();
}
public void Play()
{
Paused = false;
}
public void Pause()
{
Paused = true;
}
}