diff --git a/Shared/Sprites.cs b/Shared/Sprites.cs index d6e15e1..7aeb3a7 100644 --- a/Shared/Sprites.cs +++ b/Shared/Sprites.cs @@ -16,15 +16,22 @@ namespace SemiColinGames { } } + 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) { + public SpriteAnimation(int start, int end, int durationMs, AnimationDirection direction) { Start = start; End = end; DurationMs = durationMs; + Direction = direction; } } @@ -61,17 +68,25 @@ namespace SemiColinGames { frames.Add(new Frame(source, durationMs)); } - // TODO: handle ping-pong animations. JToken frameTags = json.SelectToken("meta.frameTags"); foreach (JToken child in frameTags.Children()) { string name = child.SelectToken("name").Value(); int start = child.SelectToken("from").Value(); int end = child.SelectToken("to").Value(); + string directionString = child.SelectToken("direction").Value(); + AnimationDirection direction = directionString == "pingpong" ? + AnimationDirection.PingPong: AnimationDirection.Forward; int durationMs = 0; for (int i = start; i <= end; i++) { durationMs += frames[i].DurationMs; } - animations[name] = new SpriteAnimation(start, end, 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); } } @@ -85,6 +100,15 @@ namespace SemiColinGames { } 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; }