using System; using System.Collections.Generic; namespace Otter { /// /// Graphic that is used for an animated sprite sheet. /// /// public class Spritemap : Image { #region Public Fields /// /// The playback speed of all animations. /// public float Speed = 1f; #endregion #region Public Properties /// /// The total number of frames on the sprite sheet. /// public int Frames { get; private set; } /// /// The total number of columns on the sprite sheet. /// public int Columns { get; private set; } /// /// The total number of rows on the spirte sheet. /// public int Rows { get; private set; } /// /// The current buffered animation. /// public TAnimType BufferedAnimation { get; private set; } /// /// Determines if the sprite is playing animations. /// public bool Active { get; private set; } /// /// Determines if the sprite is advancing its current animation. /// public bool Paused { get; private set; } /// /// The dictionary of stored animations. /// public Dictionary Anims { get; private set; } /// /// The animation currently playing. /// public TAnimType CurrentAnim { get; private set; } /// /// The current frame of the animation on the sprite sheet. /// public int CurrentFrame { get { return Anims[CurrentAnim].CurrentFrame; } set { SetFrame(value); } } /// /// The current frame index of the animation, from 0 to frame count - 1. /// public int CurrentFrameIndex { get { return Anims[CurrentAnim].CurrentFrameIndex; } set { Anims[CurrentAnim].CurrentFrameIndex = value; } } #endregion #region Constructors /// /// Create a new Spritemap from a file path. /// /// The file path to a texture to use for the sprite sheet. /// The width of the animation. /// The height of the animation. public Spritemap(string source, int width, int height) : base(source) { Initialize(width, height); } /// /// Create a new Spritemap from a Texture. /// /// The Texture to use for the sprite sheet. /// The width of a cell on the sprite sheet. /// The height of a cell on the sprite sheet. public Spritemap(Texture texture, int width, int height) : base(texture) { Initialize(width, height); } /// /// Create a new Spritemap from an AtlasTexture. /// /// The AtlasTexture to use for the sprite sheet. /// The width of a cell on the sprite sheet. /// The height of a cell on the sprite sheet. public Spritemap(AtlasTexture texture, int width, int height) : base(texture) { Initialize(width, height); } #endregion #region Private Methods protected void Initialize(int width, int height) { Anims = new Dictionary(); // Try batching later. //Batchable = true; Width = width; Height = height; ClippingRegion = new Rectangle(0, 0, Width, Height); Columns = (int)Math.Ceiling((float)TextureRegion.Width / Width); Rows = (int)Math.Ceiling((float)TextureRegion.Height / Height); Frames = Columns * Rows; UpdateTextureRegion(0); } protected override void TextureChanged() { // Dont do the same stuff as image :I } #endregion #region Indexers public Anim this[TAnimType anim] { get { return Anim(anim); } } #endregion #region Public Methods /// /// Add an animation to the list of Anims. /// /// The key to reference this animation. /// The anim value. public void Add(TAnimType a, Anim anim) { Anims.Add(a, anim); CurrentAnim = a; } /// /// Adds an animation using a string for frames and a single value for frame delay. /// /// The key to store the animation with. /// The frames of the animation from the sprite sheet. Example: "0,3,7-11,2,5" /// The delay between advancing to the next frame. /// The added animation. public Anim Add(TAnimType a, string frames, float framedelays) { var anim = new Anim(frames, framedelays.ToString()); Add(a, anim); return anim; } /// /// Add an animation using a string for frames and a string for framedelays. /// /// The key to store the animation with. /// The frames of the animation from the sprite sheet. Example: "0,3,7-11,2,5" /// The duration of time to show each frame. Example: "10,10,5,5,50" /// The added animation. public Anim Add(TAnimType a, string frames, string framedelays) { var anim = new Anim(frames, framedelays); Add(a, anim); return anim; } /// /// Add an animation to the sprite. /// /// The name of the animation. /// An array of the frames to display. /// An array of durations for each frame. /// The added animation. public Anim Add(TAnimType a, int[] frames, float[] frameDelay = null) { var anim = new Anim(frames, frameDelay); Add(a, anim); return anim; } /// /// Adds an animation using an array for frames and a single value for frame delay. /// /// The key to store the animation with. /// The frames of the animation from the sprite sheet. Example: "0,3,7-11,2,5" /// The delay between advancing to the next frame. /// The added animation. public Anim Add(TAnimType a, int[] frames, float framedelays) { var anim = new Anim(frames, new float[] { framedelays }); Add(a, anim); return anim; } /// /// Updates the animation. The sprite will not animate without this. /// public override void Update() { base.Update(); if (!Active) return; if (!Anims.ContainsKey(CurrentAnim)) return; if (Paused) return; Anims[CurrentAnim].Update(Speed); UpdateSprite(); } void UpdateSprite() { UpdateTextureRegion((int)Util.Clamp(Anims[CurrentAnim].CurrentFrame, 0, Frames)); } /// /// Updates the internal source for the texture. /// /// The frame in terms of the sprite sheet. void UpdateTextureRegion(int frame) { var top = (int)(Math.Floor((float)frame / Columns) * Height); var left = (int)((frame % Columns) * Width); if (TextureRegion != new Rectangle(left, top, Width, Height)) { NeedsUpdate = true; } TextureRegion = new Rectangle(left, top, Width, Height); } /// /// Play the desired animation. /// /// The animation to play. /// Resets the animation back to the start before playing even if this is the same animation that was already playing. public void Play(TAnimType a, bool forceReset = true) { Active = true; var pastAnim = CurrentAnim; CurrentAnim = a; if (Anims[CurrentAnim] != Anims[pastAnim] || forceReset) { Anims[CurrentAnim].Reset(); } Anims[CurrentAnim].Active = true; UpdateSprite(); } /// /// Buffers an animation but does not play it. Call Play() with no arguments to play the buffered animation. /// /// The animation to buffer. public void Buffer(TAnimType a) { BufferedAnimation = a; } /// /// Plays an animation. If no animation is specified, play the buffered animation. /// public void Play(bool forceReset = true) { if (BufferedAnimation != null) { Play(BufferedAnimation, forceReset); } else { Play(CurrentAnim, forceReset); } UpdateSprite(); } /// /// Get the animation with a specific key. /// /// The key to search with. /// The animation found. public Anim Anim(TAnimType a) { if (!Anims.ContainsKey(a)) return null; return Anims[a]; } /// /// Pause the playback of the animation. /// public void Pause() { Paused = true; } /// /// Resume the animation from the current position. /// public void Resume() { Paused = false; } /// /// Stop playback. This will reset the animation to the first frame. /// public void Stop() { Active = false; Anims[CurrentAnim].Stop(); } /// /// Set the current animation to a specific frame. /// /// The frame in terms of the animation. public void SetFrame(int frame) { if (!Active) return; Anims[CurrentAnim].CurrentFrameIndex = frame; Anims[CurrentAnim].Reset(); } /// /// Set the current animation to a specific frame and pause. /// /// The frame in terms of the animation. public void FreezeFrame(int frame) { if (!Active) return; Paused = true; Anims[CurrentAnim].CurrentFrameIndex = frame; UpdateTextureRegion(Anims[CurrentAnim].CurrentFrame); } /// /// Set the sprite to a frame on the sprite sheet itself. /// This will disable the current animation! /// /// The global frame in terms of the sprite sheet. public void SetGlobalFrame(int frame) { Active = false; UpdateTextureRegion(frame); } /// /// Resets the current animation back to the first frame. /// public void Reset() { Anims[CurrentAnim].Reset(); } /// /// Clear the list of animations. /// public void Clear() { Anims.Clear(); } #endregion } public class Spritemap : Spritemap { /// /// Create a new Spritemap from a file path. /// /// The file path to a texture to use for the sprite sheet. /// The width of the animation. /// The height of the animation. public Spritemap(string source, int width, int height) : base(source, width, height) { Initialize(width, height); } /// /// Create a new Spritemap from a Texture. /// /// The Texture to use for the sprite sheet. /// The width of a cell on the sprite sheet. /// The height of a cell on the sprite sheet. public Spritemap(Texture texture, int width, int height) : base(texture, width, height) { Initialize(width, height); } /// /// Create a new Spritemap from an AtlasTexture. /// /// The AtlasTexture to use for the sprite sheet. /// The width of a cell on the sprite sheet. /// The height of a cell on the sprite sheet. public Spritemap(AtlasTexture texture, int width, int height) : base(texture, width, height) { Initialize(width, height); } } }