#region File Description //----------------------------------------------------------------------------- // ScaledAnimation.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region File Information //----------------------------------------------------------------------------- // ScaledAnimation.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; #endregion namespace HoneycombRush { /// /// Supports animation playback. /// public class ScaledAnimation { #region Fields Texture2D animatedCharacter; Point sheetSize; public Point currentFrame; public Point frameSize; private TimeSpan lastestChangeTime; private TimeSpan timeInterval = TimeSpan.Zero; private int startFrame; private int endFrame; private int lastSubFrame = -1; bool drawWasAlreadyCalledOnce = false; public int FrameCount { get { return sheetSize.X * sheetSize.Y; } } public Vector2 Offset { get; set; } public int FrameIndex { get { return sheetSize.X * currentFrame.Y + currentFrame.X; } set { if (value >= sheetSize.X * sheetSize.Y + 1) { throw new InvalidOperationException("Specified frame index exceeds available frames"); } currentFrame.Y = value / sheetSize.X; currentFrame.X = value % sheetSize.X; } } public bool IsActive { get; private set; } #endregion #region Initialization /// /// Creates a new instance of the animation class /// /// Texture which is a sheet containing /// the animation frames. /// The size of a single frame. /// The size of the entire animation sheet. public ScaledAnimation(Texture2D frameSheet, Point size, Point frameSheetSize) { animatedCharacter = frameSheet; frameSize = size; sheetSize = frameSheetSize; Offset = Vector2.Zero; } #endregion #region Update and Render /// /// Updates the animation's progress. /// /// Game time information. /// Whether or not the animation element itself is /// currently in motion. public void Update(GameTime gameTime, bool isInMotion) { Update(gameTime, isInMotion, false); } /// /// Updates the animation's progress. /// /// Game time information. /// Whether or not the animation element itself is /// currently in motion. /// public void Update(GameTime gameTime, bool isInMotion, bool runSubAnimation) { if (IsActive && gameTime.TotalGameTime != lastestChangeTime) { // See if a time interval between frames is defined if (timeInterval != TimeSpan.Zero) { // Do nothing until an interval passes if (lastestChangeTime + timeInterval > gameTime.TotalGameTime) { return; } } lastestChangeTime = gameTime.TotalGameTime; if (FrameIndex >= FrameCount) { FrameIndex = 0; // Reset the animation } else { // Only advance the animation if the animation element is moving if (isInMotion) { if (runSubAnimation) { // Initialize the animation if (lastSubFrame == -1) { lastSubFrame = startFrame; } // Calculate the currentFrame, which depends on the current // frame in the parent animation currentFrame.Y = lastSubFrame / sheetSize.X; currentFrame.X = lastSubFrame % sheetSize.X; // Move to the next Frame lastSubFrame += 1; // Loop the animation if (lastSubFrame > endFrame) { lastSubFrame = startFrame; } } else { // Do not advance frames before the first draw operation if (drawWasAlreadyCalledOnce) { currentFrame.X++; if (currentFrame.X >= sheetSize.X) { currentFrame.X = 0; currentFrame.Y++; } if (currentFrame.Y >= sheetSize.Y) currentFrame.Y = 0; if (lastSubFrame != -1) { lastSubFrame = -1; } } } } } } } /// /// Render the animation. /// /// ScaledSpriteBatch with which the current /// frame will be rendered. /// The position to draw the current frame. /// SpriteEffect to apply to the /// current frame. public void Draw(ScaledSpriteBatch ScaledSpriteBatch, Vector2 position, SpriteEffects spriteEffect) { Draw(ScaledSpriteBatch, position, 1.0f, spriteEffect); } /// /// Render the animation. /// /// ScaledSpriteBatch with which the current frame /// will be rendered. /// The position to draw the current frame. /// Scale factor to apply to the current frame. /// SpriteEffect to apply to the /// current frame. public void Draw(ScaledSpriteBatch ScaledSpriteBatch, Vector2 position, float scale, SpriteEffects spriteEffect) { drawWasAlreadyCalledOnce = true; ScaledSpriteBatch.Draw(animatedCharacter, position + Offset, new Rectangle(frameSize.X * currentFrame.X, frameSize.Y * currentFrame.Y, frameSize.X, frameSize.Y), Color.White, 0f, Vector2.Zero, scale, spriteEffect, 0); } /// /// Causes the animation to start playing from a specified frame index. /// /// Frame index to play the animation from. public void PlayFromFrameIndex(int frameIndex) { FrameIndex = frameIndex; IsActive = true; drawWasAlreadyCalledOnce = false; } /// /// Sets the range of frames which serves as the sub animation. /// /// Start frame for the sub-animation. /// End frame for the sub-animation. public void SetSubAnimation(int startFrame, int endFrame) { this.startFrame = startFrame; this.endFrame = endFrame; } /// /// Used to set the interval between frames. /// /// The interval between frames. public void SetFrameInterval(TimeSpan interval) { timeInterval = interval; } #endregion } }