You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Newtonsoft.Json.Linq; using System.Collections.Generic;
namespace SemiColinGames { static class Sprites { public static Sprite Executioner; public static Sprite Ninja;
public static void Load(ContentManager content) { Executioner = new Sprite( Textures.Executioner, content.LoadString("sprites/ccg/executioner_female.json")); Ninja = new Sprite( Textures.Ninja, content.LoadString("sprites/ccg/ninja_female.json")); } }
enum AnimationDirection { Forward, PingPong }
struct SpriteAnimation { public readonly int Start; public readonly int End; public readonly int DurationMs; public readonly AnimationDirection Direction;
public SpriteAnimation(int start, int end, int durationMs, AnimationDirection direction) { Start = start; End = end; DurationMs = durationMs; Direction = direction; } }
struct Frame { public readonly Rectangle Source; public readonly int DurationMs;
public Frame(Rectangle source, int durationMs) { Source = source; DurationMs = durationMs; } }
class Sprite { public readonly TextureRef Texture;
private readonly Dictionary<string, SpriteAnimation> animations; private readonly List<Frame> frames;
public Sprite(TextureRef texture, string metadataJson) { Texture = texture; animations = new Dictionary<string, SpriteAnimation>();
JObject json = JObject.Parse(metadataJson);
frames = new List<Frame>(); foreach (JToken child in json.SelectToken("frames").Children()) { Rectangle source = new Rectangle( child.SelectToken("frame.x").Value<int>(), child.SelectToken("frame.y").Value<int>(), child.SelectToken("frame.w").Value<int>(), child.SelectToken("frame.h").Value<int>()); // TODO: convert all durations to floats.
int durationMs = child.SelectToken("duration").Value<int>(); frames.Add(new Frame(source, durationMs)); }
JToken frameTags = json.SelectToken("meta.frameTags"); foreach (JToken child in frameTags.Children()) { string name = child.SelectToken("name").Value<string>(); int start = child.SelectToken("from").Value<int>(); int end = child.SelectToken("to").Value<int>(); string directionString = child.SelectToken("direction").Value<string>(); AnimationDirection direction = directionString == "pingpong" ? AnimationDirection.PingPong : AnimationDirection.Forward; int durationMs = 0; for (int i = start; i <= end; i++) { durationMs += frames[i].DurationMs; } // A PingPong animation repeats every frame but the first and last.
// Therefore its duration is 2x, minus the duration of the first and last frames.
if (direction == AnimationDirection.PingPong) { durationMs = durationMs * 2 - frames[start].DurationMs - frames[end].DurationMs; }
animations[name] = new SpriteAnimation(start, end, durationMs, direction); } }
public Rectangle GetTextureSource(string animationName, int timeMs) { SpriteAnimation animation = animations[animationName]; int time = timeMs % animation.DurationMs; for (int i = animation.Start; i <= animation.End; i++) { int frameTime = frames[i].DurationMs; if (time < frameTime) { return frames[i].Source; } time -= frameTime; } if (animation.Direction == AnimationDirection.PingPong) { for (int i = animation.End - 1; i > animation.Start; i--) { int frameTime = frames[i].DurationMs; if (time < frameTime) { return frames[i].Source; } time -= frameTime; } } // We shouldn't get here, but if we did, the last frame is a fine thing to return.
return frames[animation.End].Source; } } }
|