Introduction
Even XNA is a great framework it don't have it's own animation class. So if you want to create even simply animation you have to do everything by your own, which is some situation is advantages, but for simply 2d animation is painfull. This article helps user to create class which get rid of control which you have to normally to care off.
Background
I wont cover silverlight and XNA seperatly. Reader have to know simply basics of XNA and silverlight. Mainly XNA. Main porpose is to exmplain idea of how to creat animation class which could help you futher development. There is several diferencies betweeen creating XNA app and Windows Phone Silverlight and XNA Application. Since silverlight application is based on events, so most methods parameters will be events arguments, but besides that main idea is same.
Using the code
First of all we have to create Windows Phone Game Library (4.0). Since we will use this only in xna class we have to use this type project.
As i mentioned it will by used in xna class so we have to keep XNA method naming so we need three methods:
public virtual void Draw(SpriteBatch spriteBatch)
public virtual void Load(ContentManager contentManager, GraphicsDevice graphicDevice)
public virtual void Update(double gameTime)
While creating this class it is requared to know sprites count per width and height and also spite name.
public Animated2dSpriteBase(int spritesPerWidth, int spritesPerHeight, string spriteName)
{
this.m_spriteName = spriteName;
this.m_framesCountPerHeight = spritesPerHeight;
this.m_framesCountPerWidth = spritesPerWidth;
this.m_totalFramesCount = spritesPerHeight * spritesPerWidth;
this.m_currentFrameNo = 1;
this.IntervalTime = INTERVALTIME;
this.m_timer = 0;
this.X = 0;
this.Y = 0;
this.Animate = true;
}
When loading some parameters are already declared in xna silverlight application class. Content manager came from silverlight app like (Application.Current as App).Content
and graphicDevice SharedGraphicsDeviceManager.Current.GraphicsDevice
.
public virtual void Load(ContentManager contentManager, GraphicsDevice graphicDevice)
{
m_spriteSheet = contentManager.Load<Texture2D>(m_spriteName);
m_spriteWindowWidth = m_spriteSheet.Width / m_framesCountPerWidth;
m_spriteWindowHeight = m_spriteSheet.Height / m_framesCountPerHeight;
m_spriteOutputRectangle = new Rectangle(0, 0, m_spriteWindowWidth, m_spriteWindowHeight);
}
Here sprite name which was passed through contructor is loaded from parameter contentManager.
Using Sprite bach is same as in typical XNA game class. Here each time is drawed only outuput with correct frame.
public virtual void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(m_spriteSheet, new Rectangle(X, Y, m_spriteWindowWidth, m_spriteWindowHeight), m_spriteOutputRectangle, Color.White);
}
Since silverlight xna class have only GameTimerEventArgs which contains only TimeSpan classes, We are able to get only passed time which is passed to Update method.
public virtual void Update(double gameTime)
{
if (gameTime > m_timer && Animate)
{
m_timer = gameTime + m_intervalSec;
m_currentFrameNo++;
if (m_currentFrameNo > m_totalFramesCount)
m_currentFrameNo = 1;
CalculateOutRectanglePosition();
}
}
Here if default time (m_timer
) is passed and Animation
bool flag is true we update current frame number and recalculate output rectangle position. Animate flag is property type so it is possible to turn of animation at any time and current frame will be outputed to screen.
CalculateOutRectanglePosition
main purpose it to find output rectangle position using current frame number.
private void CalculateOutRectanglePosition()
{
rowNumber = m_currentFrameNo > m_framesCountPerWidth ? 1 : (m_currentFrameNo - 1) / m_framesCountPerWidth;
rowNumber++;
if (m_currentFrameNo <= m_framesCountPerWidth)
{
m_spriteOutputRectangle.X = (m_currentFrameNo - 1) * m_spriteWindowWidth;
}
else
{
if (m_currentFrameNo % m_framesCountPerWidth == 0)
{
m_spriteOutputRectangle.X = (m_currentFrameNo - 1) % m_framesCountPerWidth * m_spriteWindowWidth;
}
else
{
m_spriteOutputRectangle.X = ((m_currentFrameNo % m_framesCountPerWidth) - 1) * m_spriteWindowWidth;
}
m_spriteOutputRectangle.Y = (rowNumber - 1) * m_spriteWindowHeight;
}
We already know which frame is current, so it is possible to calculate output rectangle position. Lets say our sprite sheet looks like this bellow and current frame is 5, so we need to find out row and column number. Then it will bee 2 and 2. When these number are calculated it is easy to calculate output rectangle position. Simply just miltiply by row number minus 1, because start position starts from 0.
The m_spriteOutputRectangle is Rectangle which it drawed to screen, so we redraw its possition only when needed. Just to remind, that current frame shows which animation frame is on screen this moment.