An Xna Animated Sprite Component for Windows Phone, PC, and Xbox
Introduction
The basics of animation are well known; by rapidly switching among a group of still images one can create the illusion that something is moving. Simply animating something isn't a challenge. In working on a game recently I found the need to come up with a better way of managing my animation state. Often times there may be multiple objects displayed on the screen that are drawn from the same sprite sheet. But each one of these objects could be in a different state in its animation. There's also the matter of getting the sprite coordinates into the program. While one could type these coordinates into the programs code that's not the most desired solution; if something in the images change it would be necessary to make changes to the code. The purpose of the code attached to this article is to address both of those problems; managing animation state and managing the information as content.
The day after concluding that I needed a better solution I was on a car ride for a few hours heading to a family reunion. What I document below is the solution I thought out the night before the drive and typed during the drive. This is a proof of concept and not final code, but it's an idea that I think others can easily extend to suit their own needs.
Prerequisites
To take advantage of the information in this article you will need to already have familiarity with XNA and handling sprites. Being a .Net technology this also means that you need to have familiarity with C# and Visual Studio. For software you need to have a PC running Windows Vista or higher and you need to have the Windows Phone Developer Tools installed (even if you don't plan on targetting Windows Phone). While the download is labeled as being for Windows Phone it is actually a package that contains the dev tools for Windows Phone, Xbox, and PC.

Running the Project
I know there are some that want to see the project running without needing to doanload ans setup the environment. For the benefit of the people in that group I've uploaded a vide to youtube in which I breifly talk through the project and then run it.
Sprite Animation Basics
When rendering a sprite you will normally have a source that has one or more images on it. You specify the coordinates of the bounding rectangle of that contains the image you want to display along with the coordinates on the screen where you want it displayed. If you want a sprite to be animated then you need to have an image for each frame of the animation to reference. You'll need to switch among the set of source images in sequence. XNA can render to the screen up to 60 frames per second (possibly faster, but let's ignore that). But you probably do not have a different version of your image for each one of those 60 frames. You will need to appropriately time when it is time to switch to the next image.
To better understand it's helpful if you first download a sprite sheet to look at. There are an uncountable number of sprite sheets out there. I decided to Bing a sprite sheet for one of the Mario Brothers games and found no shortage of them. I found this little jem. This wasn't actually created by Nintendo but was created by fans of nintendo games. Best of all the sprites on this sheet are nicely organized and labeled. There's one of Mario running that I'm going to use. So I used Paint.Net to cop the image and erase the white background so that the image would be transparent.

As your eyes follow each image in the sprite sheet you can see how the animation will look. Ideally the images in the sprite would be spaced evenly apart. For images that come from the days when available memory was measured in kilobytes you may find this to not be the case since available memory had more impact on decisions than convinience. Who ever made this sprite seemed to only try to minimize space between the images so they are not evenly spaced. But I thinnk the animation is cool and it brings back memories, so I am sticking with it. I also grabbed an image of a plane with a rotating propeller from another CodeProject.com article and found one of a bird flapping its wings. With these three pre-existing images I found that a different amount of effort was needed to get them animated (which also gives me ideas on how I can improve this code in the future). I'll start with the simplest of the images (the planes from the CodeProject.com article) and then move the the more complex.
Many thanks to Jonas Follesø for his article on the game 1945 for PocketPC and publishing it under CPOL. I took the plane images from there.
Animating the Plane
One of the files in the article is named BigPlanes.bmp. I converted it from a bitmap to a PNG so that I could make it transparent. The image contains sprites for three planes. Each one of the planes has an animated propeller. These images are evenly spaced. The first plane starts at coordinate (1,1) and is 64 pixels wide and high. After the image of the first plan is a gray 1 pixel border, and then the second plan starts at position (66,1). Because of the 1 pixel border and 64 pixel with of the images you can get the starting point of the Nth plane by taking (n*65)+1. This makes it much easier to convert this sprite sheet into an animation. I don't have to look up the starting point of each image.

I'm just going to animate the first two planes in the sheet. I'll have them as animations for different states of the same object. I got the starting X and Y positions of the three images { (1,1), (66, 1), (131, 1) } and the second three images {(196,1), (261, 1), (326, 1)}and put them in my code. For now assume that the screen is being updated 30 times per second but I only want this animation to occur at 10 frames per second. At 30fps the player will be able to smoothly move the plane around on the screen. So I will need to track how much time has passed before I advance the frame. In the following code I animate the plane and provide a way of switching from one plane animation to another. I'm leaving out some of the typical pieces of code that you may expect to find in an XNA program so that I can highlight the parts that are specific to this task.
Rectangle[] _planeSourceSpriteLocation_1 = new Rectangle[]
{
new Rectangle( 1, 1, 64, 64),
new Rectangle( 66, 1, 64, 64),
new Rectangle(131, 1, 64, 64),
};
Rectangle[] _planeSourceSpriteLocation_2 = new Rectangle[]
{
new Rectangle(196, 1, 64, 64),
new Rectangle(261, 1, 64, 64),
new Rectangle(326, 1, 64, 64),
};
Rectangle[] _planeSourceSpriteLocation_current;
int _frameNumber;
TimeSpan _frameLength;
Vector2 _position = new Vector2(100,100);
Texture2D _planeTexture;
void SetPlaneSource(int i)
{
_planeSourceSpriteLocation_current= (i==1)?
_planeSourceSpriteLocation_2 :
_planeSourceSpriteLocation_1;
}
protected override void LoadContent()
{
///code for loading sprites here
SetPlaneSource(1);
}
protected override void Update(GameTime gameTime)
{
_frameLength += gameTime.ElapsedGameTime;
//if the frame has been displayed for more than 0.1 seconds then
//advance to the next frame.
if(_frameLength.TotalSeconds > 0.1d)
{
_frameLenth -= TimeSpan.FromSeconds(0.1);
++_frameNumber;
//Ensure we haven't advanced past the last frame by looping
//back to the first frame.
if(_frameNumber >
You can see that's a lot of information to track and handle for a single sprite. This isn't the way you would want to do this for multiple sprites; the code would get messy fast. I'll show one way of organizing this information before this article is over.
Animating the Bird
For another sprite sheet I found of a bird the images were not evenly spaced, but this didn't make for much of a obstacle in using it. The bird is flapping its wings but its head is stationary. So when I defined my bounding rectangles I ensured that the birds head was in the same place in each one of rectangles. If this isn't done the bird would appear to shake when it is animated. Once I have my binding rectangles the rest of the task would be the same as it was with the plane.

The code from the previous example would work for animating this bird, though my array of rectangles would have 4 rectangles instead of 3.
Animating Mario Running
In trying to animate Mario the first real obstacle is encountered. The images in that sprite are not evenly spaced. So I used the same technique that I did on the bird; I chose a stationary part of the image and got my coordinates relative to that stationary position. When I did this I ran into a second problem; the images are not the same width. If I use a bounding rectangle that matches the minimum width of one of the images then in some of the frames parts of the animation get clipped. If I use a rectangle that matches the maximum width then I will unintentionally end up with parts of the neighboring images inappropriately showing up in some frames. I could use rectangles of various widths so that each rectangle appropriatly bound its intended frame without spilling over into the other frames, but doing that would obligate the Draw code to be modified to accomodate the rectangles needing to be drawn slightly different. I thought about making a solution to address this but decided against it. Accomodating images like this makes the code considerably more complex. After much thought I decided instead to make it a requirement that all sprites associated with an animation be of the same length. I don't enforce this within my code, but I don't support it either.
Respresenting a Sprite Animation
I've run through a few simple sprite animation scenarios and have a good feel for what I need for the code to do. what follows is one way of organizing the information needed for animating sprites into classes
Specifying Sprite Coordinates
A sprite sheet is essentially just an image that has a lot of smaller images on it. Normally when you are drawing an image from a sprite sheet you will have to specify two sets of coordinates. Let's take a look at a typical call to draw a sprite onto the screen. I've put the data types in comments.
spriteBatch.Draw(
/*Texture2D*/ sourceTexture,
/*Rectangle*/ destinationRectangle,
/*Rectangle*/ sourceRectangle,
/*Color*/ tint
);
The destination rectangle is going to depend on exactly where on the screen your object needs to be drawn which will be dependent on where within your game world that the object is currently positioned. But for the source rectangle will have less variance. Every time you draw the same object the source coordinates for the texture are going to be decided at compile time. So an attribute of the solution being saught is that it will need to be able to keep track of the source coordinates from the sprite sheet. Each source rectangle coordinates will also be associated with some length of time for which the sprite needs to be displayed. If I had an animation that was playing 15 frames per second then the length of time associated with each frame would be 1/15 of a second.
public class SpriteSource
{
public TimeSpan FrameLength { get; set; }
public double FrameLengthSeconds
{
get { return FrameLength.TotalSeconds; }
set { FrameLength = TimeSpan.FromSeconds(value); }
}
public Rectangle SourceRectangle { get; set; }
}
The FrameLengthSeconds
field looks redundant,
but since this data will be saved to a file it must be serializable. The TimeSpan
member doesn't serialize, so I have added an alias field (FrameLengthSeconds
) of type double
that will serialize.
Grouping Coordinates into Frames
An animation is a collection of frames, so I need to be able to organize my frames into a list.
A generic list class meets this need. But any given animated object could be
associated with more than one animation. For example you may have different
animations for some one walking vs some one running. You may have a
different animation for when a player is in a normal mode vs powered up. Or
you may have an animation for each direction in which a character could
walk. So my animation will have a collection of frames, but each object
could also have a collection of animations. I prefer to reference toe
animations by name so my class for storing the frames that belong to an
animation. I also need to be able to identify which frame should be
displayed at a specific time index. Since the animation shown is going
to be dependent on an objects states I'm borrowing from a XAML concept and
will call the collection of frames that represent an object in a specific
state the VisualState
.
public class VisualState
{
public VisualState()
{
SpriteSourceList = new List<SpriteSource>();
}
public SpriteSource this[TimeSpan index]
{
get {
if(TotalLength.Ticks>0)
while (index > TotalLength)
index -= TotalLength;
int i = 0;
while(index>SpriteSourceList[i].FrameLength)
{
++i;
index -= SpriteSourceList[i].FrameLength;
}
return SpriteSourceList[i];
}
}
public TimeSpan TotalLength
{
get { return TimeSpan.FromTicks(SpriteSourceList.Sum((ss) => ss.FrameLength.Ticks)); }
}
public string Name { get; set; }
public List<SpriteSource> SpriteSourceList { get; set; }
}
Grouping Animations for a Single Object
Since any object can have more than one animation a list works out fine for grouping those animations
into a single entity. Just for the sake of it I also gave the collection of animations a name (there's no
functional reason for doing this, but when debugging it helps to be able to associate the collection with
a name) and also added a member to reference the Texture2D
from which the animation will be
pulling its images.
public class AnimatedSprite
{
public string Name { get; set; }
public string PreferredTextureName { get; set; }
[XmlIgnore]
internal Texture2D CurrentTexture { get; set; }
public void SetTexture(Texture2D sourceTexture)
{
CurrentTexture = sourceTexture;
}
public List<VisualState> VisualStateList { get; set; }
public AnimatedSprite()
{
VisualStateList = new List<VisualState>();
}
public AnimatedSpriteInstance CreateInstance()
{
return new AnimatedSpriteInstance(this);
}
}
There are two things in the above code that I haven't talked about.
The CreateInstance()
method hasn't been explained nor has the reason that CurrentTexture
is marked as internal
been explained. I'll come back to the internal
marking on CurrentTexture
in a moment. Let's talk about
CreateInstance()
.
Tracking Instances of Animations
There are likely to be multiple items on the screen that are using the same animation. It would be overkill to
keep an exact duplicate of each animation for each object. But there is also data that must be specific to each
instance. So I've seperated the common data from the instance data. The AnimatedSprite
class contains
the common data. Each object that has it's own animation will need to have instance data which can be acquired from
the CreateInstance()
class. This method instantiates a new AnimatedSpriteInstance()
. I've
not made the constructor for this class public so the only way to create one is to first have an AnimatedSprite
and then call the CreateInstance()
method.
The most vital pieces of information that this class contains are a reference to the animated spite from which the
instance was made (in the Parent
property), the time progress of the animated (in the _timeOffset
field), and the state, which determins which animation set is being used (in the PresentState
property, but manipulated
through the StateName
property). If for some reason I decide that a specific instance of an animation should pull
from a different texture I've exposed a property called TextureOverride
that defaults to null
. Setting this
to another texture will cause the animation instance to use that new texture. Setting it back to null
will cause it
to revert back to its original texture. There is also a Position
member that you can use to set where the sprite will
appear on the screen.
The animation is advanced through AnimationInstance.Update(GameTime)
. In general you would call this early within
the Draw method. But if an animation needed to be synced with some timed event then it would be better to call this in your game's
Update()
method. The Draw()
method may not get called every cycle if something slows a game down, but Update
will always be called. All animations will loop once the last frame is reached. So the AnimatedSpriteInstance.Update()
method will reset the _timeOffset
when ever it reaches the end of the animation.
The Draw
method will take care of drawing the appropriate frame of the sprite. You only need to give it the
SpriteBatch
instance to use. You might recall the the SpriteBatch
method has a number of
overloaded Draw
methods. I've only used one in this example code, but you may want to change this to use
one of the overloaded methods that provides more options. You could either expose these options by adding new members
onto the AnimatedSpriteInstance.Draw()
method or you could add new properties to hold values that would
be passed to the additional parameters. For example, I've added a Color Tint { get; set; }
property that will
get passed as the Tine
parameter for the animation.
public class AnimatedSpriteInstance
{
private TimeSpan _timeOffset;
public Vector2 Position { get; set; }
public AnimatedSprite Parent { get; internal set; }
public SpriteBatch TargetSpriteBatch { get; set; }
public Texture2D TextureOverride { get; set; }
public VisualState PresentState { get; protected set; }
public Color Tint { get; set; }
private string _stateName;
public string StateName
{
get { return _stateName; }
set
{
VisualState newState =
(from VisualState s in Parent.VisualStateList where s.Name.Equals(value) select s).FirstOrDefault();
if(newState==null)
throw new IndexOutOfRangeException(String.Format("There is no state named {0} in this sprite", value));
_stateName = value;
PresentState = newState;
}
}
public AnimatedSpriteInstance()
{
Tint = Color.White;
TextureOverride = null;
Reset();
}
public AnimatedSpriteInstance(AnimatedSprite parent):this()
{
Parent = parent;
Reset();
}
public void Reset()
{
_timeOffset = TimeSpan.Zero;
if (Parent != null)
{
PresentState = Parent.VisualStateList[0];
_stateName = PresentState.Name;
}
}
public void Update(GameTime gameTime)
{
_timeOffset += gameTime.ElapsedGameTime;
while (_timeOffset >= PresentState.TotalLength)
_timeOffset -= PresentState.TotalLength;
}
public void Draw(SpriteBatch targetBatch)
{
var spriteSource = PresentState[_timeOffset].SourceRectangle;
targetBatch.Draw( (TextureOverride ?? Parent.CurrentTexture),Position, spriteSource, Color.White);
}
public void Draw()
{
Draw(TargetSpriteBatch);
}
}
Class Diagram

Making Support for an Animation to be Content
Part of the reason that I wrote this code is I wanted to start removing the specifics of an animation from my code and put it into anothe resource that some one without a programming skill set to modify and create the animations. My first step in this is to allow the information on the sprite locations to be specified in an XML file. While I don't expect most artist to be able to be familiar with XML files it is an incremental step closer to a human (artist) friendly solution. The next step would be to create a tool so that some one could specify the locations of the sprites graphically. I won't be tackling that part in this article. So I only want to take about creating the XML file here and consuming it in an XNA project. I'll take on creating a graphical tool for manipulating this information after I've used this code for several more scenarios. I don't know what changes future needs will bring to the code and don't want to yet have a graphical editor that would possibly require being updated as I adjust the animation code. Once the animation code further matures and handles a wider range of scenarios then I will look at making a graphical tool.
XNA has a facility called the content pipeline made to handle the processing of content in a project. If you are new to XNA you've probably been happily using the content pipeline without having to consider its inner workings. The content pipeline already has what is needed to handle some common file types (MP3, PNG, 3D Model Formats, and so on) and I wanted to extend it to also be able to handle my animations. Once done I would be able to use the same technique for games made for the PC, the Xbox, and Windows Phone.
Content Pipeline Basics
Assets that go through the content pipeline are processed in four different objects: an Importer, a processor, a writer, and a reader. The Importerreads the asset and passes it off to the processor. The processor looks at the data that was read from the asset and interprets it, building some other object that represents the form that you want the data to be in when the content is loaded. The Writer serializes the object to a stream. And the Reader will be used by the game at runtime to load the saved content. XNA defines generic base classes for implementing each one of these types of object
Of those four types of objects three of them are used at design time (importer, processor, writer) and one is used at runtime (reader). The three design-time classes can be part of one project. The runtime class must be deployed with your project and a version of the runtime class must be created for each platform on which your game will run. In my case the runtime projects will just be projects that share the same files since there will be no difference in the source code from Windows Phone to PC to Xbox. Let's look at how I implemented each one of these classes in more detail. I started off by creating a new project. In the new project dialog there is an option for a Content Extension project under the XNA group. After I made the project I started adding the following to it.
Content Importer
XNA defines the generic base class ContentImporter<T>
class for implementing a
content importer. This class only loads the data into something that can be
passed to the processor, but otherwise does not processing on the file.
The content importer must declare the extension for the types of files it
processes and define the processor to be used along with a friendly display
name. All of this information is passed through an the ContentImporterAttribute
on the class.
[ContentImporter(".animatedSprite", DefaultProcessor = "AnimatedSpriteProcessor", DisplayName = "Animated Sprite Importer")]
public class AnimatedSpriteImporter: ContentImporter<AnimatedSpriteDescription>
{
public override AnimatedSpriteDescription Import(string filename, ContentImporterContext context)
{
string spriteXml = File.ReadAllText(filename);
return new AnimatedSpriteDescription(Path.GetFileNameWithoutExtension(filename), spriteXml);
}
}
AnimatedSpriteDescription
is a class I've defined for holding the contents of the file. It only contains two fields,
AnimatedSpriteXml
and AnimationName
both of which are strings.
public class AnimatedSpriteDescription
{
public string AnimatedSpriteXml { get; set; }
public string AnimationName { get; set; }
public AnimatedSpriteDescription(string name, string xml)
{
AnimationName = name;
AnimatedSpriteXml = xml;
}
}
Content Processor
The content processor converts the data it receives from the ContentImporter
to an object. The generic
base class for implementing a ContentProcessor
as you may have guessed in ContentProcessor<InputType, OutputType>
.
InputType
needs the type of your importer and OutputType
should be set to the type that the processor
produces. I just
introduced you to the importer. The output of my processor is
an AnimatedSprite
; the same type that I described
in the begining of this article. The only method that needs to
be overridden in the derived class is the Process
method.
[ContentProcessor(DisplayName = "Animated Sprite Processor")] public class AnimatedSpriteProcessor : ContentProcessor<AnimatedSpriteDescription, AnimatedSprite> { public override AnimatedSprite Process(AnimatedSpriteDescription input, ContentProcessorContext context) { XmlSerializer xs = new XmlSerializer(typeof(AnimatedSprite)); StringReader sr = new StringReader(input.AnimatedSpriteXml); var entry = (AnimatedSprite)xs.Deserialize(sr); //---- //additional processing done here //---- return entry; } }
Since I went with an XML format you can see that I didn't have to do much processing.
Content Writer
The last design time component through which your asset will pass is a class
derived from ContentTypeWriter<ContentType>
. It has a few methods
that need to be overridden. As you would expect there is a Write
method
that must serialize your content. As arguments it receives a ContentWriter
and the object produced by the ContentProcessor
that needs to be written.
There are two other methods that need to be overridden too: GetRuntimeType
and GetRuntimeReader
. The method GetRuntimeType
should return
a string that identifies the assembly and the type within the assembly that must be
instantiated for holding your content. GetRuntimeType
returns a string that
identifies the assembly and the class within the assembly that contains the ContentReader
.
class AnimatedSpriteWriter: ContentTypeWriter<AnimatedSprite>
{
protected override void Write(ContentWriter output, AnimatedSprite value)
{
XmlSerializer xs = new XmlSerializer(typeof(AnimatedSprite));
System.IO.StringWriter sw = new StringWriter();
xs.Serialize(sw, value);
output.Write(value.Name);
output.Write(sw.ToString());
}
public override string GetRuntimeType(Microsoft.Xna.Framework.Content.Pipeline.TargetPlatform targetPlatform)
{
return "J2i.Net.AnimatedSriteLibrary, AnimatedSprite, Version=1.0.0.0, Culture=neutral";
}
public override string GetRuntimeReader(Microsoft.Xna.Framework.Content.Pipeline.TargetPlatform targetPlatform)
{
return "J2i.Net.AnimatedSriteLibrary, AnimatedSpriteReader, Version=1.0.0.0, Culture=neutral";
}
}
ContentTypeReader
The other three content classes that I've talked about all execute on your PC while you are building a
game. None of them get pushed out to the machine or device that will run the game. The ContentTypeReader
differs from these in that it must be distributed with the game. Since your XNA game could be running on one of three
platforms (Windows Phone, Xbox, and PC) you will need to have three versions of your content reader. The source code
for all three can be identical. You can even use the same file to compile all three versions. But each one of these platforms
has it's own binary format for executables so you won't have the exact same binary for all three platforms. For now
I am going to stick with targetting PC only. Adding the support needed for Windows Phone and Xbox is a trivial effort
so I will save that task for later.
Since the ContentTypeReader
will be used by the same code that uses the AnimatedSprite
that I built earlier I find it appropriate to make it part of the same project. I added a new class to that project
and had it inherit from ContentTypeReader<AnimatedSprite>
and overrode the Read
method. As arguments this method receives a reference to a ContentReader
and an instantiated object
that the contents could be written to. Since I used XML serialization to write the asset I can use the Deserialize
method on the XmlSerializer
class once I read the the data from
the ContentTypeReader
.
public class AnimatedSpriteReader : ContentTypeReader<AnimatedSprite> { protected override AnimatedSprite Read(ContentReader input, AnimatedSprite existingInstance) { var xs = new System.Xml.Serialization.XmlSerializer(typeof(AnimatedSprite)); string name = input.ReadString(); string info = input.ReadString(); System.IO.StringReader sr = new System.IO.StringReader(info); var animatedSprite = (AnimatedSprite)xs.Deserialize(sr); return animatedSprite; } }
Creating the Animation
Creating an animation is just a matter of typing an XML file with the right coordinates and giving it the
.animatedSprite
extension. I've typed the code for the plane
animation in the following. You might notice that each frame has it's own FrameLengthSeconds
setting. This is because not every frame has to be the same length. I've also given the animation two states;
one called Main
that will be the animation's default state and another called Green
.
<?xml version="1.0" encoding="utf-8"?>
<AnimatedSprite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Plane Map</Name>
<VisualStateList>
<!-- The first visual state for the main animation -->
<VisualState>
<Name>Main</Name>
<SpriteSourceList>
<SpriteSource>
<FrameLengthSeconds>0.1</FrameLengthSeconds>
<SourceRectangle>
<X>1</X>
<Y>1</Y>
<Width>64</Width>
<Height>64</Height>
</SourceRectangle>
</SpriteSource>
<SpriteSource>
<FrameLengthSeconds>0.1</FrameLengthSeconds>
<SourceRectangle>
<X>67</X>
<Y>1</Y>
<Width>64</Width>
<Height>64</Height>
</SourceRectangle>
</SpriteSource>
<SpriteSource>
<FrameLengthSeconds>0.1</FrameLengthSeconds>
<SourceRectangle>
<X>133</X>
<Y>1</Y>
<Width>64</Width>
<Height>64</Height>
</SourceRectangle>
</SpriteSource>
</SpriteSourceList>
</VisualState>
<!-- The second visual state for the Green animation -->
<VisualState>
<Name>Green</Name>
<SpriteSourceList>
<SpriteSource>
<FrameLengthSeconds>0.1</FrameLengthSeconds>
<SourceRectangle>
<X>199</X>
<Y>1</Y>
<Width>64</Width>
<Height>64</Height>
</SourceRectangle>
</SpriteSource>
<SpriteSource>
<FrameLengthSeconds>0.1</FrameLengthSeconds>
<SourceRectangle>
<X>265</X>
<Y>1</Y>
<Width>64</Width>
<Height>64</Height>
</SourceRectangle>
</SpriteSource>
<SpriteSource>
<FrameLengthSeconds>0.1</FrameLengthSeconds>
<SourceRectangle>
<X>331</X>
<Y>1</Y>
<Width>64</Width>
<Height>64</Height>
</SourceRectangle>
</SpriteSource>
</SpriteSourceList>
</VisualState>
</VisualStateList>
</AnimatedSprite>
To use the sprite I had to do a few things to the content project in my XNA game
- Add a Reference to the animation design time project
- Add the
.animatedSprite
file(s) to the
content project
- Add the image resources to the content project

In the Game project there are also a few things that need to be done. I need to add a reference to the
project that contains the runtime information. I put both the ContentTypeReader
and the
class declarations for my sprites in the same project, though this isn't mandatory.
Once that is done I can load the sprites animations, images, and start
displaying them. Recall that you must create an instance of AnimatedSpriteInstance
to display
something on screen. Once the sprite instance is created the only methods I need to call to keep it animating
are Update
and Draw
. The class will keep track of everything else on it's own.
private AnimatedSprite _animatedSprite;
private Texture2D _spriteTexture;
private AnimatedSpriteInstance _spriteInstance;
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
//Load assets
_spriteTexture = Content.Load<Texture2D>("allies");
_animatedSprite = Content.Load<AnimatedSprite>("MyAnimatedSprite");
SpriteFont sf = Content.Load<SpriteFont>("DebugFont");
//Give the animatedSprite object its sprite sheet
_animatedSprite.SetTexture(_spriteTexture);
//Create an instance of the animation for display
_spriteInstance = _animatedSprite.CreateInstance();
}
protected override void Update(GameTime gameTime)
{
_spriteInstance.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
// TODO: Add your drawing code here
spriteBatch.Begin();
_spriteInstance.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
When an animation has multiple visual states I can switch between the states by setting the StateName
value on the instance.
_spriteInstance.StateName="NewState";
Running on Other Platforms
I mentioned earlier that you would need to make a version of the run time code for each platform on which you intend it to run. When I started off I was only running this code on a PC. Making it run on a Windows Phone or Xbox requires little effort. First let's take a look at the project layout.

I have the game as a Windows XNA project, the game's content project, a game class library (which contains the runtime classes), and the content extension project (which contains the design time components). Of these projects only the Windows XNA game project and the class library need to be converted. The others will remain untouched. Right-click on the game project and select either the option to copy the project for Xbox 360 or Windows Phone.

Both the game and the class library on which it depends will be copied into a Windows
Phone or Xbox project project. Perhaps I should use the word "copy" because the same source files are
being referenced by the two projects. If you make a change to a file in one project since the file
is shared you will see the change in the other also. When you try to compile
the project it will fail, stating that it cannot find the class definition
for System.Xml.Serialization.XmlSerialization
. On Windows Phone and Xbox
this class exists in it's own assembly while on the PC it exists in the
System.Xml.dll
assembly. So you will need to add a reference to the
System.Xml.Serialization.dll
assembly in both the runtime project and the
game project.
Future Improvements
I've written this as a proof of concept. There are some other features I want it to support but rather than
trying to get it to do everything I wanted to do at once I decided it was best to start small.
Part of my goal was to get this working during the car ride and that limits
how much I can get done. Though I don't view that time limit as a bad thing;
the goal for this project was to get something that is initially satisficing.
In using what I have so far I had some realizations such as needing support for "debugging" sprites. I implemented
a quick solution to fit my needs so that I could see the frame index being
used at any point in time. I also will need support for drawing sprites at
something other than their natural size and support for rotation in the
future. For now I am just going to keep track of needs for the future and
modify this code enough so that it meets the needs for the game I am working
on now (I don't want to get side tracked with scope creep). I've also added
a Scale
property for enlarging the image, though the
implementation in the code isn't the implementation I want to have in the
final code.
发表评论
Bnft4W Video lesbiennes sexe porno ladies Also visit my blog post sexshop
am8TeL Some really quality articles on this web site , bookmarked.
LBHZXb Really informative blog.Really thank you! Awesome.
joex2U wow, awesome blog.Much thanks again. Much obliged.
GKwd39 I truly appreciate this article.Thanks Again. Will read on
lRUsz6 Well I truly liked reading it. This tip offered by you is very useful for accurate planning.
khZFDr What as up to every single one, it as in fact a nice for me to go to see this web page, it contains priceless Information.
we came across a cool internet site which you may possibly love. Take a look if you want
CCjPEd I think this is a real great blog article.Thanks Again. Really Cool.
8KsYXS
hasvvT Wow! Thank you! I always wanted to write on my website something like that. Can I include a fragment of your post to my website?
WWouxX
6T2SM5 Wow! Thank you! I always needed to write on my website something like that. Can I take a portion of your post to my website?
8ZY4if It as exhausting to search out educated people on this matter, but you sound like you know what you are speaking about! Thanks
LEGmL7 Im no expert, but I think you just crafted an excellent point. You naturally comprehend what youre talking about, and I can actually get behind that. Thanks for being so upfront and so honest.
KEMM5S I truly appreciate this post. Really Great.
jIqGPH This is really interesting, You are a very skilled blogger. I have joined your rss feed and look forward to seeking more of your wonderful post. Also, I have shared your site in my social networks!
kFufi9 I really like and appreciate your post. Keep writing.
21sN8V Really informative article post.Really looking forward to read more. Cool.
DTysDY It's onerous to find educated folks on this matter, but you sound like you understand what you're talking about! Thanks
y3zKIb Thanks a bunch for sharing this with all of us you actually know what you are talking about! Bookmarked. Please also visit my site =). We could have a link exchange contract between us!
54NuN6 I've learn some excellent stuff here. Definitely value bookmarking for revisiting. I wonder how much effort you place to make any such magnificent informative website.
cKztXI I appreciate you sharing this blog article. Much obliged.
3uciYP Great, thanks for sharing this blog.Thanks Again. Awesome.
WoHF5f Very good article post.Really looking forward to read more. Awesome.
YbY1OO I appreciate you sharing this article post. Awesome.
2eF50z Looking forward to reading more. Great blog.Much thanks again. Awesome.
3AEqNt Really informative blog article. Really Cool.
4O8gAX Fantastic article post.Really looking forward to read more.
af9gPt I cannot thank you enough for the blog article.Much thanks again. Much obliged.
SSs6gQ This is one awesome blog post. Really Cool.