Skip to content

Instantly share code, notes, and snippets.

@Bocom
Created July 23, 2012 02:00
Show Gist options
  • Save Bocom/3161664 to your computer and use it in GitHub Desktop.
Save Bocom/3161664 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace WanderfulEngine
{
public enum Direction
{
Down,
DownRight,
Right,
UpRight,
Up,
UpLeft,
Left,
DownLeft
}
public struct AnimationFile
{
public string Texture { get; set; }
public Dictionary<string, int> Size { get; set; }
public int AnimationCount { get; set; }
public Dictionary<string, AnimationContent> Animations { get; set; }
}
public struct AnimationContent
{
public bool Loop { get; set; }
public float DefaultFrameLength { get; set; }
public FrameContent[] Frames { get; set; }
}
public struct FrameContent
{
public float Length { get; set; }
public int X { get; set; }
public int Y { get; set; }
}
/// <summary>
/// A frame of animation.
/// </summary>
public struct AnimationFrame
{
public float Length;
public Rectangle Source;
#region Properties
public Vector2 BottomCenter
{
get
{
return new Vector2(Source.Width / 2.0f, Source.Height);
}
}
public Vector2 Center
{
get { return new Vector2(Source.Width / 2.0f, Source.Height / 2.0f); }
}
#endregion
public AnimationFrame(float length)
{
Length = length;
Source = Rectangle.Empty;
}
public AnimationFrame(float length, Rectangle source)
: this(length)
{
Source = source;
}
}
public class AnimationCollection
{
public Texture2D Texture { get; set; }
public Vector2 FrameSize { get; set; }
public int AnimationCount { get { return Animations.Count; } }
public Dictionary<string, Animation> Animations { get; set; }
public Animation this[string index]
{
get { return Animations[index]; }
set { Animations[index] = value; }
}
public AnimationCollection()
{
Animations = new Dictionary<string, Animation>();
}
}
public class Animation
{
#region Fields
private string name;
public int FrameCount;
private AnimationFrame[] frames;
private float frameLength;
private Texture2D texture;
private bool loop;
private bool done;
#endregion
#region Properties
public string Name
{
get { return name; }
set { name = value; }
}
public Texture2D Texture
{
get { return texture; }
set { texture = value; }
}
public AnimationFrame[] Frames
{
get { return frames; }
set
{
frames = value;
FrameCount = frames.Length;
}
}
public AnimationFrame this[int index]
{
get { return frames[index]; }
set { frames[index] = value; }
}
public bool IsDone
{
get { return done; }
}
public bool Loop
{
get { return loop; }
set { loop = value; }
}
public float DefaultFrameLength
{
get { return frameLength; }
set { frameLength = value; }
}
#endregion
public Animation(string name)
{
Name = name;
loop = true;
done = false;
}
public Animation(string name, Texture2D texture)
: this(name)
{
Texture = texture;
}
public Animation(string name, Texture2D texture, int count)
: this(name, texture)
{
Frames = new AnimationFrame[count];
}
public static AnimationCollection Parse(
AnimationFile af,
Texture2D texture)
{
if (texture == null)
return new AnimationCollection();
int width = (int)af.Size["Width"];
int height = (int)af.Size["Height"];
Vector2 frameSize = new Vector2(width, height);
AnimationCollection output = new AnimationCollection();
output.Texture = texture;
output.FrameSize = frameSize;
foreach (KeyValuePair<string, AnimationContent> animationObj in af.Animations)
{
AnimationContent def = animationObj.Value;
string animationName = animationObj.Key.ToLower();
Animation animation = new Animation(animationName, texture);
float frameLength = def.DefaultFrameLength;
animation.DefaultFrameLength = frameLength;
animation.Loop = def.Loop;
FrameContent[] frames = def.Frames;
animation.Frames = new AnimationFrame[frames.Length];
for (int i = 0; i < frames.Length; i++)
{
FrameContent frameObj = frames[i];
AnimationFrame frame = new AnimationFrame();
frame.Length = frameObj.Length;
frame.Source = new Rectangle(
(int)(frameObj.X * frameSize.X),
(int)(frameObj.Y * frameSize.Y),
(int)frameSize.X,
(int)frameSize.Y);
animation.Frames[i] = frame;
}
output.Animations.Add(animationName, animation);
}
return output;
}
}
}
using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Newtonsoft.Json;
namespace WanderfulEngine
{
public class AnimationPlayer
{
#region Fields
private Animation currentAnimation;
private Animation nextAnimation;
private int frameIndex;
private float time;
private GraphicsDevice graphics;
#endregion
#region Properties
public Animation CurrentAnimation
{
get { return currentAnimation; }
}
public Animation NextAnimation
{
get { return nextAnimation; }
}
public AnimationFrame CurrentFrame
{
get { return currentAnimation.Frames[frameIndex]; }
}
public int CurrentFrameIndex
{
get { return frameIndex; }
}
#endregion
public AnimationPlayer(GraphicsDevice graphics)
{
this.graphics = graphics;
}
/// <summary>
/// Create a simple animation based on certain parameters.
/// UNTESTED
/// </summary>
/// <returns></returns>
public Animation CreateAnimation(Texture2D texture, string name,
int count, Vector2 frameDimensions, float length,
int directions)
{
Animation ani = new Animation(name, texture, count);
Rectangle sourceRect = new Rectangle();
sourceRect.Width = (int)frameDimensions.X;
sourceRect.Height = (int)frameDimensions.Y;
for (int d = 0; d < directions; d++)
{
for (int i = 0; i < count; i++)
{
sourceRect.X = (i * (int)frameDimensions.X);
sourceRect.Y = (d * (int)frameDimensions.Y);
ani.Frames[d + i] = new AnimationFrame(length, sourceRect);
}
}
return ani;
}
/// <summary>
/// Create a simple animation based on certain parameters.
/// UNTESTED
/// </summary>
/// <returns></returns>
public Animation CreateAnimation(Texture2D texture, string name,
int count, Vector2 frameDimensions, int oY, float length)
{
Animation ani = new Animation(name, texture, count);
Rectangle sourceRect = new Rectangle();
sourceRect.Width = (int)frameDimensions.X;
sourceRect.Height = (int)frameDimensions.Y;
for (int i = 0; i < count; i++)
{
sourceRect.X = (i * (int)frameDimensions.X);
sourceRect.Y = (oY * (int)frameDimensions.Y);
ani.Frames[i] = new AnimationFrame(length, sourceRect);
}
return ani;
}
public AnimationCollection LoadAnimation(ContentManager content, string filename)
{
string realPath = Path.GetFullPath(Path.Combine(content.RootDirectory, "Animations", filename));
string rawDef = File.ReadAllText(realPath);
AnimationFile definition = JsonConvert.DeserializeObject<AnimationFile>(rawDef);
string textureName = definition.Texture;
Texture2D texture;
try
{
if (textureName.StartsWith("Content/"))
textureName = textureName.Replace("Content/", "");
texture = content.Load<Texture2D>(textureName);
}
catch (ContentLoadException)
{
try
{
FileStream stream = new FileStream(
Path.GetFullPath(textureName), FileMode.Open);
texture = Texture2D.FromStream(graphics, stream);
stream.Close();
}
catch (Exception e) { throw e; }
}
catch (Exception e) { throw e; }
return Animation.Parse(definition, texture);
}
public AnimationCollection LoadAnimation(string filename, string path)
{
string realPath = filename;
if (string.IsNullOrEmpty(path))
realPath = Path.GetFullPath(Path.Combine(path, filename));
string rawDef = File.ReadAllText(realPath);
AnimationFile definition = JsonConvert.DeserializeObject<AnimationFile>(rawDef);
string textureName = definition.Texture;
Texture2D texture;
try
{
FileStream stream = new FileStream(
Path.GetFullPath(textureName), FileMode.Open);
texture = Texture2D.FromStream(graphics, stream);
stream.Close();
}
catch (Exception e) { throw e; }
return Animation.Parse(definition, texture);
}
public void PlayAnimation(Animation animation)
{
if (CurrentAnimation == animation)
return;
currentAnimation = animation;
frameIndex = 0;
time = 0.0f;
nextAnimation = null;
}
public void Update(GameTime gameTime)
{
if (currentAnimation == null)
return;
time += (float)gameTime.ElapsedGameTime.TotalSeconds;
float frameLength = CurrentFrame.Length == 0.0f ?
CurrentAnimation.DefaultFrameLength :
CurrentFrame.Length;
if (time > frameLength)
{
time -= frameLength;
if (CurrentAnimation.Loop)
frameIndex = ++frameIndex % CurrentAnimation.FrameCount;
else
{
frameIndex = Math.Min(++frameIndex, currentAnimation.FrameCount - 1);
if (frameIndex == CurrentAnimation.FrameCount && nextAnimation != null)
PlayAnimation(nextAnimation);
}
}
}
public void Draw(GameTime gameTime, SpriteBatch spriteBatch,
Vector2 position, SpriteEffects spriteEffects)
{
if (currentAnimation == null)
return;
Rectangle destination = new Rectangle(
(int)position.X, (int)position.Y,
CurrentFrame.Source.Width,
CurrentFrame.Source.Height);
spriteBatch.Draw(currentAnimation.Texture,
destination,
CurrentFrame.Source,
Color.White,
0.0f,
CurrentFrame.Center,
spriteEffects,
0.0f);
}
}
}
{
"Texture": "Content/Monster",
"Size": {
"Width": 32,
"Height": 48
},
"AnimationCount": 8,
"Animations": {
"idle-down": {
"Loop": false,
"DefaultFrameLength": 1.0,
"Frames": [
{
"Length": 0.0,
"X": 0,
"Y": 0
}
]
},
"moving-down": {
"Loop": true,
"DefaultFrameLength": 0.07,
"Frames": [
{
"Length": 0.0,
"X": 0,
"Y": 0
},
{
"Length": 0.0,
"X": 1,
"Y": 0
},
{
"Length": 0.0,
"X": 2,
"Y": 0
},
{
"Length": 0.0,
"X": 3,
"Y": 0
},
{
"Length": 0.0,
"X": 4,
"Y": 0
},
{
"Length": 0.0,
"X": 5,
"Y": 0
},
{
"Length": 0.0,
"X": 6,
"Y": 0
},
{
"Length": 0.0,
"X": 7,
"Y": 0
}
]
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment