From e1fe51826178f9b9c787d7a10938e6c66d624dc1 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Fri, 20 Sep 2013 16:42:55 +0200 Subject: [PATCH] Bounding boxes for spine-csharp. --- spine-csharp/spine-csharp_xna.csproj | 2 + .../src/Attachments/AtlasAttachmentLoader.cs | 2 + .../src/Attachments/AttachmentType.cs | 2 +- .../src/Attachments/BoundingBoxAttachment.cs | 54 ++ spine-csharp/src/SkeletonBounds.cs | 275 +++++++++ spine-csharp/src/SkeletonJson.cs | 584 +++++++++--------- spine-xna/example/data/spineboy.json | 2 +- spine-xna/example/src/ExampleGame.cs | 30 +- spine-xna/src/SkeletonRenderer.cs | 2 - 9 files changed, 658 insertions(+), 295 deletions(-) create mode 100644 spine-csharp/src/Attachments/BoundingBoxAttachment.cs create mode 100644 spine-csharp/src/SkeletonBounds.cs diff --git a/spine-csharp/spine-csharp_xna.csproj b/spine-csharp/spine-csharp_xna.csproj index e7c596053..373273e0d 100644 --- a/spine-csharp/spine-csharp_xna.csproj +++ b/spine-csharp/spine-csharp_xna.csproj @@ -101,11 +101,13 @@ + + diff --git a/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs b/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs index 5af5e897e..9fca7fa24 100644 --- a/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs +++ b/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs @@ -49,6 +49,8 @@ namespace Spine { attachment.RegionOriginalWidth = region.originalWidth; attachment.RegionOriginalHeight = region.originalHeight; return attachment; + case AttachmentType.boundingbox: + return new BoundingBoxAttachment(name); } throw new Exception("Unknown attachment type: " + type); } diff --git a/spine-csharp/src/Attachments/AttachmentType.cs b/spine-csharp/src/Attachments/AttachmentType.cs index 1d768a9aa..824e7ab9f 100644 --- a/spine-csharp/src/Attachments/AttachmentType.cs +++ b/spine-csharp/src/Attachments/AttachmentType.cs @@ -25,6 +25,6 @@ namespace Spine { public enum AttachmentType { - region, regionSequence + region, regionsequence, boundingbox } } diff --git a/spine-csharp/src/Attachments/BoundingBoxAttachment.cs b/spine-csharp/src/Attachments/BoundingBoxAttachment.cs new file mode 100644 index 000000000..8e87f7da0 --- /dev/null +++ b/spine-csharp/src/Attachments/BoundingBoxAttachment.cs @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +using System; + +namespace Spine { + /** Attachment that has a polygon for bounds checking. */ + public class BoundingBoxAttachment : Attachment { + public float[] Vertices { get; set; } + + public BoundingBoxAttachment (string name) + : base(name) { + } + + /** @param worldVertices Must have at least the same as this attachment's vertices. */ + public void ComputeWorldVertices (float x, float y, Bone bone, float[] worldVertices) { + x += bone.WorldX; + y += bone.WorldY; + float m00 = bone.M00; + float m01 = bone.M01; + float m10 = bone.M10; + float m11 = bone.M11; + float[] vertices = Vertices; + for (int i = 0, n = vertices.Length; i < n; i += 2) { + float px = vertices[i]; + float py = vertices[i + 1]; + worldVertices[i] = px * m00 + py * m01 + x; + worldVertices[i + 1] = px * m10 + py * m11 + y; + } + } + } +} diff --git a/spine-csharp/src/SkeletonBounds.cs b/spine-csharp/src/SkeletonBounds.cs new file mode 100644 index 000000000..e1f7cd495 --- /dev/null +++ b/spine-csharp/src/SkeletonBounds.cs @@ -0,0 +1,275 @@ +/******************************************************************************* + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + public class SkeletonBounds { + private bool aabb; + private List polygonPool = new List(); + + public List BoundingBoxes { get; private set; } + public List Polygons { get; private set; } + + private float minX; + public float MinX { + get { + if (!aabb) aabbCompute(); + return minX; + } + private set { + minX = value; + } + } + + private float maxX; + public float MaxX { + get { + if (!aabb) aabbCompute(); + return maxX; + } + private set { + maxX = value; + } + } + + private float minY; + public float MinY { + get { + if (!aabb) aabbCompute(); + return minY; + } + private set { + minY = value; + } + } + + private float maxY; + public float MaxY { + get { + if (!aabb) aabbCompute(); + return maxY; + } + private set { + maxY = value; + } + } + + public float Width { + get { + if (!aabb) aabbCompute(); + return maxX - minX; + } + } + + public float Height { + get { + if (!aabb) aabbCompute(); + return maxY - minY; + } + } + + public SkeletonBounds () { + BoundingBoxes = new List(); + Polygons = new List(); + } + + public void Update (Skeleton skeleton) { + aabb = false; + + List boundingBoxes = BoundingBoxes; + List polygons = Polygons; + List slots = skeleton.Slots; + int slotCount = slots.Count; + float x = skeleton.X, y = skeleton.Y; + + boundingBoxes.Clear(); + foreach (Polygon polygon in polygons) { + polygonPool.Add(polygon); + } + polygons.Clear(); + + for (int i = 0; i < slotCount; i++) { + Slot slot = slots[i]; + BoundingBoxAttachment boundingBox = slot.Attachment as BoundingBoxAttachment; + if (boundingBox == null) continue; + boundingBoxes.Add(boundingBox); + + Polygon polygon = null; + int poolCount = polygonPool.Count; + if (poolCount > 0) { + polygon = polygonPool[poolCount - 1]; + polygonPool.RemoveAt(poolCount - 1); + } else + polygon = new Polygon(); + polygons.Add(polygon); + polygon.Count = boundingBox.Vertices.Length; + if (polygon.Vertices == null || polygon.Vertices.Length < polygon.Count) polygon.Vertices = new float[polygon.Count]; + boundingBox.ComputeWorldVertices(x, y, slot.Bone, polygon.Vertices); + } + } + + private void aabbCompute () { + float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; + List polygons = Polygons; + for (int i = 0, n = polygons.Count; i < n; i++) { + Polygon polygon = polygons[i]; + float[] vertices = polygon.Vertices; + for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) { + float x = vertices[ii]; + float y = vertices[ii + 1]; + minX = Math.Min(minX, x); + minY = Math.Min(minY, y); + maxX = Math.Max(maxX, x); + maxY = Math.Max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + aabb = true; + } + + + /** Returns true if the axis aligned bounding box contains the point. */ + public bool AabbContainsPoint (float x, float y) { + if (!aabb) aabbCompute(); + return x >= minX && x <= maxX && y >= minY && y <= maxY; + } + + /** Returns true if the axis aligned bounding box intersects the line segment. */ + public bool AabbIntersectsSegment (float x1, float y1, float x2, float y2) { + if (!aabb) aabbCompute(); + float minX = this.minX; + float minY = this.minY; + float maxX = this.maxX; + float maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + float m = (y2 - y1) / (x2 - x1); + float y = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + float x = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + } + + /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ + public bool AabbIntersectsSkeleton (SkeletonBounds bounds) { + if (!aabb) aabbCompute(); + if (!bounds.aabb) bounds.aabbCompute(); + return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; + } + + /** Returns true if the bounding box attachment contains the point. */ + public bool ContainsPoint (int index, float x, float y) { + Polygon polygon = Polygons[index]; + float[] vertices = polygon.Vertices; + int nn = polygon.Count; + + int prevIndex = nn - 2; + bool inside = false; + for (int ii = 0; ii < nn; ii += 2) { + float vertexY = vertices[ii + 1]; + float prevY = vertices[prevIndex + 1]; + if (vertexY < y && prevY >= y || prevY < y && vertexY >= y) { + float vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + return inside; + } + + /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if {@link #aabbContainsPoint(float, float)} return true. */ + public BoundingBoxAttachment ContainsPoint (float x, float y) { + List boundingBoxes = BoundingBoxes; + for (int i = 0, n = boundingBoxes.Count; i < n; i++) + if (ContainsPoint(i, x, y)) return boundingBoxes[i]; + return null; + } + + /** Returns true if the bounding box attachment contains the point. The bounding box must be in the SkeletonBounds. */ + public bool containsPoint (BoundingBoxAttachment attachment, float x, float y) { + int index = BoundingBoxes.IndexOf(attachment); + return index == -1 ? false : ContainsPoint(index, x, y); + } + + /** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually + * more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} return true. */ + public BoundingBoxAttachment IntersectsSegment (float x1, float y1, float x2, float y2) { + List boundingBoxes = BoundingBoxes; + for (int i = 0, n = boundingBoxes.Count; i < n; i++) { + BoundingBoxAttachment attachment = boundingBoxes[i]; + if (IntersectsSegment(attachment, x1, y1, x2, y2)) return attachment; + } + return null; + } + + /** Returns true if the bounding box attachment contains the line segment. */ + public bool IntersectsSegment (BoundingBoxAttachment attachment, float x1, float y1, float x2, float y2) { + int index = BoundingBoxes.IndexOf(attachment); + return index == -1 ? false : IntersectsSegment(index, x1, y1, x2, y2); + } + + /** Returns true if the bounding box attachment contains the line segment. */ + public bool IntersectsSegment (int index, float x1, float y1, float x2, float y2) { + Polygon polygon = Polygons[index]; + float[] vertices = polygon.Vertices; + int nn = polygon.Count; + + float width12 = x1 - x2, height12 = y1 - y2; + float det1 = x1 * y2 - y1 * x2; + float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (int ii = 0; ii < nn; ii += 2) { + float x4 = vertices[ii], y4 = vertices[ii + 1]; + float det2 = x3 * y4 - y3 * x4; + float width34 = x3 - x4, height34 = y3 - y4; + float det3 = width12 * height34 - height12 * width34; + float x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + float y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; + } + x3 = x4; + y3 = y4; + + } + return false; + } + } +} + +public class Polygon { + public float[] Vertices { get; set; } + public int Count { get; set; } +} diff --git a/spine-csharp/src/SkeletonJson.cs b/spine-csharp/src/SkeletonJson.cs index c24f2faf1..c8f50da6d 100644 --- a/spine-csharp/src/SkeletonJson.cs +++ b/spine-csharp/src/SkeletonJson.cs @@ -21,39 +21,40 @@ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -using System; -using System.IO; -using System.Collections.Generic; - + ******************************************************************************/ + +using System; +using System.IO; +using System.Collections.Generic; + #if WINDOWS_STOREAPP using System.Threading.Tasks; using Windows.Storage; -#endif - +#endif + namespace Spine { - public class SkeletonJson { - static public String TIMELINE_SCALE = "scale"; - static public String TIMELINE_ROTATE = "rotate"; - static public String TIMELINE_TRANSLATE = "translate"; - static public String TIMELINE_ATTACHMENT = "attachment"; - static public String TIMELINE_COLOR = "color"; - - static public String ATTACHMENT_REGION = "region"; - static public String ATTACHMENT_REGION_SEQUENCE = "regionSequence"; - - private AttachmentLoader attachmentLoader; - public float Scale { get; set; } - - public SkeletonJson (Atlas atlas) : this(new AtlasAttachmentLoader(atlas)) { - } - - public SkeletonJson (AttachmentLoader attachmentLoader) { - if (attachmentLoader == null) throw new ArgumentNullException("attachmentLoader cannot be null."); - this.attachmentLoader = attachmentLoader; - Scale = 1; - } + public class SkeletonJson { + static public String TIMELINE_SCALE = "scale"; + static public String TIMELINE_ROTATE = "rotate"; + static public String TIMELINE_TRANSLATE = "translate"; + static public String TIMELINE_ATTACHMENT = "attachment"; + static public String TIMELINE_COLOR = "color"; + + static public String ATTACHMENT_REGION = "region"; + static public String ATTACHMENT_REGION_SEQUENCE = "regionSequence"; + + private AttachmentLoader attachmentLoader; + public float Scale { get; set; } + + public SkeletonJson (Atlas atlas) + : this(new AtlasAttachmentLoader(atlas)) { + } + + public SkeletonJson (AttachmentLoader attachmentLoader) { + if (attachmentLoader == null) throw new ArgumentNullException("attachmentLoader cannot be null."); + this.attachmentLoader = attachmentLoader; + Scale = 1; + } #if WINDOWS_STOREAPP private async Task ReadFile(string path) { @@ -69,248 +70,257 @@ namespace Spine { public SkeletonData ReadSkeletonData (String path) { return this.ReadFile(path).Result; } -#else - public SkeletonData ReadSkeletonData (String path) { - using (StreamReader reader = new StreamReader(path)) { - SkeletonData skeletonData = ReadSkeletonData(reader); - skeletonData.Name = Path.GetFileNameWithoutExtension(path); - return skeletonData; - } - } -#endif - - public SkeletonData ReadSkeletonData (TextReader reader) { - if (reader == null) throw new ArgumentNullException("reader cannot be null."); - - SkeletonData skeletonData = new SkeletonData(); - - var root = Json.Deserialize(reader) as Dictionary; - if (root == null) throw new Exception("Invalid JSON."); - - // Bones. - foreach (Dictionary boneMap in (List)root["bones"]) { - BoneData parent = null; - if (boneMap.ContainsKey("parent")) { - parent = skeletonData.FindBone((String)boneMap["parent"]); - if (parent == null) - throw new Exception("Parent bone not found: " + boneMap["parent"]); - } - BoneData boneData = new BoneData((String)boneMap["name"], parent); - boneData.Length = GetFloat(boneMap, "length", 0) * Scale; - boneData.X = GetFloat(boneMap, "x", 0) * Scale; - boneData.Y = GetFloat(boneMap, "y", 0) * Scale; - boneData.Rotation = GetFloat(boneMap, "rotation", 0); - boneData.ScaleX = GetFloat(boneMap, "scaleX", 1); - boneData.ScaleY = GetFloat(boneMap, "scaleY", 1); - boneData.InheritScale = GetBoolean (boneMap, "inheritScale", true); - boneData.InheritRotation = GetBoolean (boneMap, "inheritRotation", true); - skeletonData.AddBone(boneData); - } - - // Slots. - if (root.ContainsKey("slots")) { - var slots = (List)root["slots"]; - foreach (Dictionary slotMap in slots) { - String slotName = (String)slotMap["name"]; - String boneName = (String)slotMap["bone"]; - BoneData boneData = skeletonData.FindBone(boneName); - if (boneData == null) - throw new Exception("Slot bone not found: " + boneName); - SlotData slotData = new SlotData(slotName, boneData); - - if (slotMap.ContainsKey("color")) { - String color = (String)slotMap["color"]; - slotData.R = ToColor(color, 0); - slotData.G = ToColor(color, 1); - slotData.B = ToColor(color, 2); - slotData.A = ToColor(color, 3); - } - - if (slotMap.ContainsKey("attachment")) +#else + public SkeletonData ReadSkeletonData (String path) { + using (StreamReader reader = new StreamReader(path)) { + SkeletonData skeletonData = ReadSkeletonData(reader); + skeletonData.Name = Path.GetFileNameWithoutExtension(path); + return skeletonData; + } + } +#endif + + public SkeletonData ReadSkeletonData (TextReader reader) { + if (reader == null) throw new ArgumentNullException("reader cannot be null."); + + SkeletonData skeletonData = new SkeletonData(); + + var root = Json.Deserialize(reader) as Dictionary; + if (root == null) throw new Exception("Invalid JSON."); + + // Bones. + foreach (Dictionary boneMap in (List)root["bones"]) { + BoneData parent = null; + if (boneMap.ContainsKey("parent")) { + parent = skeletonData.FindBone((String)boneMap["parent"]); + if (parent == null) + throw new Exception("Parent bone not found: " + boneMap["parent"]); + } + BoneData boneData = new BoneData((String)boneMap["name"], parent); + boneData.Length = GetFloat(boneMap, "length", 0) * Scale; + boneData.X = GetFloat(boneMap, "x", 0) * Scale; + boneData.Y = GetFloat(boneMap, "y", 0) * Scale; + boneData.Rotation = GetFloat(boneMap, "rotation", 0); + boneData.ScaleX = GetFloat(boneMap, "scaleX", 1); + boneData.ScaleY = GetFloat(boneMap, "scaleY", 1); + boneData.InheritScale = GetBoolean(boneMap, "inheritScale", true); + boneData.InheritRotation = GetBoolean(boneMap, "inheritRotation", true); + skeletonData.AddBone(boneData); + } + + // Slots. + if (root.ContainsKey("slots")) { + var slots = (List)root["slots"]; + foreach (Dictionary slotMap in slots) { + String slotName = (String)slotMap["name"]; + String boneName = (String)slotMap["bone"]; + BoneData boneData = skeletonData.FindBone(boneName); + if (boneData == null) + throw new Exception("Slot bone not found: " + boneName); + SlotData slotData = new SlotData(slotName, boneData); + + if (slotMap.ContainsKey("color")) { + String color = (String)slotMap["color"]; + slotData.R = ToColor(color, 0); + slotData.G = ToColor(color, 1); + slotData.B = ToColor(color, 2); + slotData.A = ToColor(color, 3); + } + + if (slotMap.ContainsKey("attachment")) slotData.AttachmentName = (String)slotMap["attachment"]; if (slotMap.ContainsKey("additive")) - slotData.AdditiveBlending = (bool)slotMap["additive"]; - - skeletonData.AddSlot(slotData); - } - } - - // Skins. - if (root.ContainsKey("skins")) { - var skinMap = (Dictionary)root["skins"]; - foreach (KeyValuePair entry in skinMap) { - Skin skin = new Skin(entry.Key); - foreach (KeyValuePair slotEntry in (Dictionary)entry.Value) { - int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key); - foreach (KeyValuePair attachmentEntry in ((Dictionary)slotEntry.Value)) { - Attachment attachment = ReadAttachment(skin, attachmentEntry.Key, (Dictionary)attachmentEntry.Value); - skin.AddAttachment(slotIndex, attachmentEntry.Key, attachment); - } - } - skeletonData.AddSkin(skin); - if (skin.Name == "default") - skeletonData.DefaultSkin = skin; - } - } - - - // Animations. - if (root.ContainsKey("animations")) { - var animationMap = (Dictionary)root["animations"]; - foreach (KeyValuePair entry in animationMap) - ReadAnimation(entry.Key, (Dictionary)entry.Value, skeletonData); - } - - skeletonData.Bones.TrimExcess(); - skeletonData.Slots.TrimExcess(); - skeletonData.Skins.TrimExcess(); - skeletonData.Animations.TrimExcess(); - return skeletonData; - } - - private Attachment ReadAttachment (Skin skin, String name, Dictionary map) { - if (map.ContainsKey("name")) - name = (String)map["name"]; - - AttachmentType type = AttachmentType.region; - if (map.ContainsKey("type")) - type = (AttachmentType)Enum.Parse(typeof(AttachmentType), (String)map["type"], false); - Attachment attachment = attachmentLoader.NewAttachment(skin, type, name); - - if (attachment is RegionAttachment) { - RegionAttachment regionAttachment = (RegionAttachment)attachment; - regionAttachment.X = GetFloat(map, "x", 0) * Scale; - regionAttachment.Y = GetFloat(map, "y", 0) * Scale; - regionAttachment.ScaleX = GetFloat(map, "scaleX", 1); - regionAttachment.ScaleY = GetFloat(map, "scaleY", 1); - regionAttachment.Rotation = GetFloat(map, "rotation", 0); - regionAttachment.Width = GetFloat(map, "width", 32) * Scale; - regionAttachment.Height = GetFloat(map, "height", 32) * Scale; - regionAttachment.UpdateOffset(); - } - - return attachment; - } - - private float GetFloat (Dictionary map, String name, float defaultValue) { - if (!map.ContainsKey(name)) - return (float)defaultValue; - return (float)map[name]; - } - - private bool GetBoolean (Dictionary map, String name, bool defaultValue) { - if (!map.ContainsKey(name)) - return (bool)defaultValue; - return (bool)map[name]; - } - - public static float ToColor (String hexString, int colorIndex) { - if (hexString.Length != 8) - throw new ArgumentException("Color hexidecimal length must be 8, recieved: " + hexString); - return Convert.ToInt32(hexString.Substring(colorIndex * 2, 2), 16) / (float)255; - } - - private void ReadAnimation (String name, Dictionary map, SkeletonData skeletonData) { - var timelines = new List(); - float duration = 0; - - if (map.ContainsKey("bones")) { - var bonesMap = (Dictionary)map["bones"]; - foreach (KeyValuePair entry in bonesMap) { - String boneName = entry.Key; - int boneIndex = skeletonData.FindBoneIndex(boneName); - if (boneIndex == -1) - throw new Exception("Bone not found: " + boneName); - - var timelineMap = (Dictionary)entry.Value; - foreach (KeyValuePair timelineEntry in timelineMap) { - var values = (List)timelineEntry.Value; - String timelineName = (String)timelineEntry.Key; - if (timelineName.Equals(TIMELINE_ROTATE)) { - RotateTimeline timeline = new RotateTimeline(values.Count); - timeline.BoneIndex = boneIndex; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - timeline.SetFrame(frameIndex, time, (float)valueMap["angle"]); - ReadCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.Frames[timeline.FrameCount * 2 - 2]); - - } else if (timelineName.Equals(TIMELINE_TRANSLATE) || timelineName.Equals(TIMELINE_SCALE)) { - TranslateTimeline timeline; - float timelineScale = 1; - if (timelineName.Equals(TIMELINE_SCALE)) - timeline = new ScaleTimeline(values.Count); - else { - timeline = new TranslateTimeline(values.Count); - timelineScale = Scale; - } - timeline.BoneIndex = boneIndex; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - float x = valueMap.ContainsKey("x") ? (float)valueMap["x"] : 0; - float y = valueMap.ContainsKey("y") ? (float)valueMap["y"] : 0; - timeline.SetFrame(frameIndex, time, (float)x * timelineScale, (float)y * timelineScale); - ReadCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.Frames[timeline.FrameCount * 3 - 3]); - - } else - throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); - } - } - } - - if (map.ContainsKey("slots")) { - var slotsMap = (Dictionary)map["slots"]; - foreach (KeyValuePair entry in slotsMap) { - String slotName = entry.Key; - int slotIndex = skeletonData.FindSlotIndex(slotName); - var timelineMap = (Dictionary)entry.Value; - - foreach (KeyValuePair timelineEntry in timelineMap) { - var values = (List)timelineEntry.Value; - String timelineName = (String)timelineEntry.Key; - if (timelineName.Equals(TIMELINE_COLOR)) { - ColorTimeline timeline = new ColorTimeline(values.Count); - timeline.SlotIndex = slotIndex; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - String c = (String)valueMap["color"]; - timeline.setFrame(frameIndex, time, ToColor(c, 0), ToColor(c, 1), ToColor(c, 2), ToColor(c, 3)); - ReadCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.Frames[timeline.FrameCount * 5 - 5]); - - } else if (timelineName.Equals(TIMELINE_ATTACHMENT)) { - AttachmentTimeline timeline = new AttachmentTimeline(values.Count); - timeline.SlotIndex = slotIndex; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - timeline.setFrame(frameIndex++, time, (String)valueMap["name"]); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.Frames[timeline.FrameCount - 1]); - - } else - throw new Exception("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); - } - } + slotData.AdditiveBlending = (bool)slotMap["additive"]; + + skeletonData.AddSlot(slotData); + } + } + + // Skins. + if (root.ContainsKey("skins")) { + var skinMap = (Dictionary)root["skins"]; + foreach (KeyValuePair entry in skinMap) { + Skin skin = new Skin(entry.Key); + foreach (KeyValuePair slotEntry in (Dictionary)entry.Value) { + int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key); + foreach (KeyValuePair attachmentEntry in ((Dictionary)slotEntry.Value)) { + Attachment attachment = ReadAttachment(skin, attachmentEntry.Key, (Dictionary)attachmentEntry.Value); + if (attachment != null) skin.AddAttachment(slotIndex, attachmentEntry.Key, attachment); + } + } + skeletonData.AddSkin(skin); + if (skin.Name == "default") + skeletonData.DefaultSkin = skin; + } + } + + + // Animations. + if (root.ContainsKey("animations")) { + var animationMap = (Dictionary)root["animations"]; + foreach (KeyValuePair entry in animationMap) + ReadAnimation(entry.Key, (Dictionary)entry.Value, skeletonData); + } + + skeletonData.Bones.TrimExcess(); + skeletonData.Slots.TrimExcess(); + skeletonData.Skins.TrimExcess(); + skeletonData.Animations.TrimExcess(); + return skeletonData; + } + + private Attachment ReadAttachment (Skin skin, String name, Dictionary map) { + if (map.ContainsKey("name")) + name = (String)map["name"]; + + AttachmentType type = AttachmentType.region; + if (map.ContainsKey("type")) + type = (AttachmentType)Enum.Parse(typeof(AttachmentType), (String)map["type"], false); + Attachment attachment = attachmentLoader.NewAttachment(skin, type, name); + + RegionAttachment regionAttachment = attachment as RegionAttachment; + if (regionAttachment != null) { + regionAttachment.X = GetFloat(map, "x", 0) * Scale; + regionAttachment.Y = GetFloat(map, "y", 0) * Scale; + regionAttachment.ScaleX = GetFloat(map, "scaleX", 1); + regionAttachment.ScaleY = GetFloat(map, "scaleY", 1); + regionAttachment.Rotation = GetFloat(map, "rotation", 0); + regionAttachment.Width = GetFloat(map, "width", 32) * Scale; + regionAttachment.Height = GetFloat(map, "height", 32) * Scale; + regionAttachment.UpdateOffset(); + } + + BoundingBoxAttachment boundingBox = attachment as BoundingBoxAttachment; + if (boundingBox != null) { + List values = (List)map["vertices"]; + float[] vertices = new float[values.Count]; + for (int i = 0, n = values.Count; i < n; i++) + vertices[i] = (float)values[i]; + boundingBox.Vertices = vertices; + } + + return attachment; + } + + private float GetFloat (Dictionary map, String name, float defaultValue) { + if (!map.ContainsKey(name)) + return (float)defaultValue; + return (float)map[name]; + } + + private bool GetBoolean (Dictionary map, String name, bool defaultValue) { + if (!map.ContainsKey(name)) + return (bool)defaultValue; + return (bool)map[name]; + } + + public static float ToColor (String hexString, int colorIndex) { + if (hexString.Length != 8) + throw new ArgumentException("Color hexidecimal length must be 8, recieved: " + hexString); + return Convert.ToInt32(hexString.Substring(colorIndex * 2, 2), 16) / (float)255; + } + + private void ReadAnimation (String name, Dictionary map, SkeletonData skeletonData) { + var timelines = new List(); + float duration = 0; + + if (map.ContainsKey("bones")) { + var bonesMap = (Dictionary)map["bones"]; + foreach (KeyValuePair entry in bonesMap) { + String boneName = entry.Key; + int boneIndex = skeletonData.FindBoneIndex(boneName); + if (boneIndex == -1) + throw new Exception("Bone not found: " + boneName); + + var timelineMap = (Dictionary)entry.Value; + foreach (KeyValuePair timelineEntry in timelineMap) { + var values = (List)timelineEntry.Value; + String timelineName = (String)timelineEntry.Key; + if (timelineName.Equals(TIMELINE_ROTATE)) { + RotateTimeline timeline = new RotateTimeline(values.Count); + timeline.BoneIndex = boneIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + timeline.SetFrame(frameIndex, time, (float)valueMap["angle"]); + ReadCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.Frames[timeline.FrameCount * 2 - 2]); + + } else if (timelineName.Equals(TIMELINE_TRANSLATE) || timelineName.Equals(TIMELINE_SCALE)) { + TranslateTimeline timeline; + float timelineScale = 1; + if (timelineName.Equals(TIMELINE_SCALE)) + timeline = new ScaleTimeline(values.Count); + else { + timeline = new TranslateTimeline(values.Count); + timelineScale = Scale; + } + timeline.BoneIndex = boneIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + float x = valueMap.ContainsKey("x") ? (float)valueMap["x"] : 0; + float y = valueMap.ContainsKey("y") ? (float)valueMap["y"] : 0; + timeline.SetFrame(frameIndex, time, (float)x * timelineScale, (float)y * timelineScale); + ReadCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.Frames[timeline.FrameCount * 3 - 3]); + + } else + throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + } + + if (map.ContainsKey("slots")) { + var slotsMap = (Dictionary)map["slots"]; + foreach (KeyValuePair entry in slotsMap) { + String slotName = entry.Key; + int slotIndex = skeletonData.FindSlotIndex(slotName); + var timelineMap = (Dictionary)entry.Value; + + foreach (KeyValuePair timelineEntry in timelineMap) { + var values = (List)timelineEntry.Value; + String timelineName = (String)timelineEntry.Key; + if (timelineName.Equals(TIMELINE_COLOR)) { + ColorTimeline timeline = new ColorTimeline(values.Count); + timeline.SlotIndex = slotIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + String c = (String)valueMap["color"]; + timeline.setFrame(frameIndex, time, ToColor(c, 0), ToColor(c, 1), ToColor(c, 2), ToColor(c, 3)); + ReadCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.Frames[timeline.FrameCount * 5 - 5]); + + } else if (timelineName.Equals(TIMELINE_ATTACHMENT)) { + AttachmentTimeline timeline = new AttachmentTimeline(values.Count); + timeline.SlotIndex = slotIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + timeline.setFrame(frameIndex++, time, (String)valueMap["name"]); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.Frames[timeline.FrameCount - 1]); + + } else + throw new Exception("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); + } + } } if (map.ContainsKey("draworder")) { @@ -344,22 +354,22 @@ namespace Spine { } timelines.Add(timeline); duration = Math.Max(duration, timeline.Frames[timeline.FrameCount - 1]); - } - - timelines.TrimExcess(); - skeletonData.AddAnimation(new Animation(name, timelines, duration)); - } - - private void ReadCurve (CurveTimeline timeline, int frameIndex, Dictionary valueMap) { - if (!valueMap.ContainsKey("curve")) - return; - Object curveObject = valueMap["curve"]; - if (curveObject.Equals("stepped")) - timeline.SetStepped(frameIndex); - else if (curveObject is List) { - List curve = (List)curveObject; - timeline.SetCurve(frameIndex, (float)curve[0], (float)curve[1], (float)curve[2], (float)curve[3]); - } - } - } -} + } + + timelines.TrimExcess(); + skeletonData.AddAnimation(new Animation(name, timelines, duration)); + } + + private void ReadCurve (CurveTimeline timeline, int frameIndex, Dictionary valueMap) { + if (!valueMap.ContainsKey("curve")) + return; + Object curveObject = valueMap["curve"]; + if (curveObject.Equals("stepped")) + timeline.SetStepped(frameIndex); + else if (curveObject is List) { + List curve = (List)curveObject; + timeline.SetCurve(frameIndex, (float)curve[0], (float)curve[1], (float)curve[2], (float)curve[3]); + } + } + } +} diff --git a/spine-xna/example/data/spineboy.json b/spine-xna/example/data/spineboy.json index a61222ec1..4357f8bb4 100644 --- a/spine-xna/example/data/spineboy.json +++ b/spine-xna/example/data/spineboy.json @@ -1 +1 @@ -{"bones":[{"name":"root"},{"name":"hip","parent":"root","x":0.64,"y":114.41},{"name":"left upper leg","parent":"hip","length":50.39,"x":14.45,"y":2.81,"rotation":-89.09},{"name":"pelvis","parent":"hip","x":1.41,"y":-6.57},{"name":"right upper leg","parent":"hip","length":45.76,"x":-18.27,"rotation":-101.13},{"name":"torso","parent":"hip","length":85.82,"x":-6.42,"y":1.97,"rotation":94.95},{"name":"left lower leg","parent":"left upper leg","length":56.45,"x":51.78,"y":3.46,"rotation":-16.65},{"name":"left shoulder","parent":"torso","length":44.19,"x":78.96,"y":-15.75,"rotation":-156.96},{"name":"neck","parent":"torso","length":18.38,"x":83.64,"y":-1.78,"rotation":0.9},{"name":"right lower leg","parent":"right upper leg","length":58.52,"x":50.21,"y":0.6,"rotation":-10.7},{"name":"right shoulder","parent":"torso","length":49.95,"x":81.9,"y":6.79,"rotation":130.6},{"name":"head","parent":"neck","length":68.28,"x":19.09,"y":6.97,"rotation":-8.94},{"name":"left arm","parent":"left shoulder","length":35.62,"x":44.19,"y":-0.01,"rotation":28.16},{"name":"left foot","parent":"left lower leg","length":46.5,"x":64.02,"y":-8.67,"rotation":102.43},{"name":"right arm","parent":"right shoulder","length":36.74,"x":49.95,"y":-0.12,"rotation":40.12},{"name":"right foot","parent":"right lower leg","length":45.45,"x":64.88,"y":0.04,"rotation":110.3},{"name":"left hand","parent":"left arm","length":11.52,"x":35.62,"y":0.07,"rotation":2.7},{"name":"right hand","parent":"right arm","length":15.32,"x":36.9,"y":0.34,"rotation":2.35}],"slots":[{"name":"left shoulder","bone":"left shoulder","attachment":"left-shoulder"},{"name":"left arm","bone":"left arm","attachment":"left-arm"},{"name":"left hand","bone":"left hand","attachment":"left-hand"},{"name":"left foot","bone":"left foot","attachment":"left-foot"},{"name":"left lower leg","bone":"left lower leg","attachment":"left-lower-leg"},{"name":"left upper leg","bone":"left upper leg","attachment":"left-upper-leg"},{"name":"pelvis","bone":"pelvis","attachment":"pelvis"},{"name":"right foot","bone":"right foot","attachment":"right-foot"},{"name":"right lower leg","bone":"right lower leg","attachment":"right-lower-leg"},{"name":"right upper leg","bone":"right upper leg","attachment":"right-upper-leg"},{"name":"torso","bone":"torso","attachment":"torso"},{"name":"neck","bone":"neck","attachment":"neck"},{"name":"head","bone":"head","attachment":"head"},{"name":"eyes","bone":"head","attachment":"eyes"},{"name":"right shoulder","bone":"right shoulder","attachment":"right-shoulder","additive":true},{"name":"right arm","bone":"right arm","attachment":"right-arm"},{"name":"right hand","bone":"right hand","attachment":"right-hand"}],"skins":{"default":{"eyes":{"eyes":{"x":28.94,"y":-32.92,"rotation":-86.9,"width":34,"height":27},"eyes-closed":{"x":28.77,"y":-32.86,"rotation":-86.9,"width":34,"height":27}},"head":{"head":{"x":53.94,"y":-5.75,"rotation":-86.9,"width":121,"height":132}},"left arm":{"left-arm":{"x":15.11,"y":-0.44,"rotation":33.84,"width":35,"height":29}},"left foot":{"left-foot":{"x":24.35,"y":8.88,"rotation":3.32,"width":65,"height":30}},"left hand":{"left-hand":{"x":0.75,"y":1.86,"rotation":31.14,"width":35,"height":38}},"left lower leg":{"left-lower-leg":{"x":24.55,"y":-1.92,"rotation":105.75,"width":49,"height":64}},"left shoulder":{"left-shoulder":{"x":23.74,"y":0.11,"rotation":62.01,"width":34,"height":53}},"left upper leg":{"left-upper-leg":{"x":26.12,"y":-1.85,"rotation":89.09,"width":33,"height":67}},"neck":{"neck":{"x":9.42,"y":-3.66,"rotation":-100.15,"width":34,"height":28}},"pelvis":{"pelvis":{"x":-4.83,"y":10.62,"width":63,"height":47}},"right arm":{"right-arm":{"x":18.34,"y":-2.64,"rotation":94.32,"width":21,"height":45}},"right foot":{"right-foot":{"x":19.02,"y":8.47,"rotation":1.52,"width":67,"height":30}},"right hand":{"right-hand":{"x":6.82,"y":1.25,"rotation":91.96,"width":32,"height":32}},"right lower leg":{"right-lower-leg":{"x":23.28,"y":-2.59,"rotation":111.83,"width":51,"height":64}},"right shoulder":{"right-shoulder":{"x":25.86,"y":0.03,"rotation":134.44,"width":52,"height":51}},"right upper leg":{"right-upper-leg":{"x":23.03,"y":0.25,"rotation":101.13,"width":44,"height":70}},"torso":{"torso":{"x":44.57,"y":-7.08,"rotation":-94.95,"width":68,"height":92}}}},"events":{"behind":{},"headAttach":{},"headPop":{}},"animations":{"drawOrder":{"bones":{"head":{"rotate":[{"time":0,"angle":0},{"time":0.4827,"angle":-11.07,"curve":"stepped"},{"time":0.8965,"angle":-11.07},{"time":1.3103,"angle":1.38},{"time":1.7931,"angle":12.91},{"time":2.1379,"angle":1.24},{"time":2.6206,"angle":-16.12,"curve":"stepped"},{"time":3.3103,"angle":-16.12},{"time":3.6551,"angle":1.31},{"time":4,"angle":359.99}],"translate":[{"time":0,"x":0,"y":0,"curve":[0.19,0.4,0.586,0.75]},{"time":0.2758,"x":57.88,"y":-35.72,"curve":[0.39,0.54,0.632,0.72]},{"time":0.4827,"x":87.26,"y":-87.89,"curve":[0.325,0.23,0.587,0.36]},{"time":0.6896,"x":28.89,"y":-114.62,"curve":[0.383,0.23,0.736,0.55]},{"time":0.8965,"x":-76.58,"y":-124.98,"curve":[0.129,0.21,0.547,0.64]},{"time":1.1034,"x":-154.37,"y":-77.13,"curve":[0.354,0.48,0.729,0.9]},{"time":1.3103,"x":-181.02,"y":18.56,"curve":[0.063,0.15,0.52,0.62]},{"time":1.5862,"x":-150.38,"y":128.67,"curve":[0.381,0.54,0.778,1]},{"time":1.7931,"x":-112.08,"y":146.28,"curve":[0.242,0,0.626,0.45]},{"time":1.931,"x":-63.7,"y":111.22,"curve":[0.398,0.35,0.786,0.76]},{"time":2.1379,"x":-48.94,"y":-1.55,"curve":[0.188,0.21,0.575,0.61]},{"time":2.3448,"x":-91.69,"y":-91.93,"curve":[0.362,0.51,0.766,1]},{"time":2.6206,"x":-142.79,"y":-126.83,"curve":[0.227,0.34,0.593,0.75]},{"time":2.7586,"x":-176.7,"y":-98.32,"curve":[0.26,0.4,0.612,0.71]},{"time":2.8965,"x":-163.95,"y":-24.04,"curve":[0.338,0.37,0.676,0.71]},{"time":2.9655,"x":-150.17,"y":10.71,"curve":[0.387,0.61,0.741,1]},{"time":3.1034,"x":-102.44,"y":45.92,"curve":[0.31,0.24,0.648,0.58]},{"time":3.2413,"x":-53.99,"y":70.39,"curve":[0.325,0.29,0.663,0.63]},{"time":3.3793,"x":1.88,"y":55.54,"curve":[0.387,0.33,0.769,0.73]},{"time":3.5862,"x":34.26,"y":36.13,"curve":[0.206,0.28,0.596,0.67]},{"time":3.7931,"x":23.94,"y":1.01,"curve":[0.373,0.56,0.759,1]},{"time":4,"x":0,"y":0}],"scale":[{"time":0.8275,"x":1,"y":1},{"time":1.3103,"x":0.742,"y":0.742},{"time":1.7931,"x":1,"y":1},{"time":2.1379,"x":1.502,"y":1.502},{"time":2.6206,"x":1,"y":1},{"time":2.9655,"x":0.707,"y":0.707},{"time":3.3793,"x":1,"y":1}]}},"events":[{"time":0,"name":"headPop","string":"pop.wav"},{"time":1.3103,"name":"behind"},{"time":2.9655,"name":"behind"},{"time":4,"name":"headAttach","string":"attach.wav"}],"draworder":[{"time":0.6206,"offsets":[{"slot":"head","offset":-12},{"slot":"eyes","offset":-12}]},{"time":1.7931,"offsets":[{"slot":"head","offset":3},{"slot":"eyes","offset":3}]},{"time":2.6206,"offsets":[{"slot":"head","offset":-12},{"slot":"eyes","offset":-12}]},{"time":3.5862,"offsets":[]}]},"jump":{"bones":{"hip":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":0.9333,"angle":0,"curve":"stepped"},{"time":1.3666,"angle":0}],"translate":[{"time":0,"x":-11.57,"y":-3},{"time":0.2333,"x":-16.2,"y":-19.43},{"time":0.3333,"x":7.66,"y":-8.48,"curve":[0.057,0.06,0.712,1]},{"time":0.3666,"x":15.38,"y":5.01},{"time":0.4666,"x":-7.84,"y":57.22},{"time":0.6,"x":-10.81,"y":96.34,"curve":[0.241,0,1,1]},{"time":0.7333,"x":-7.01,"y":54.7},{"time":0.8,"x":-10.58,"y":32.2},{"time":0.9333,"x":-31.99,"y":0.45},{"time":1.0666,"x":-12.48,"y":-29.47},{"time":1.3666,"x":-11.57,"y":-3}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left upper leg":{"rotate":[{"time":0,"angle":17.13},{"time":0.2333,"angle":44.35},{"time":0.3333,"angle":16.46},{"time":0.4,"angle":-9.88},{"time":0.4666,"angle":-11.42},{"time":0.5666,"angle":23.46},{"time":0.7666,"angle":71.82},{"time":0.9333,"angle":65.53},{"time":1.0666,"angle":51.01},{"time":1.3666,"angle":17.13}],"translate":[{"time":0,"x":-3,"y":-2.25,"curve":"stepped"},{"time":0.9333,"x":-3,"y":-2.25,"curve":"stepped"},{"time":1.3666,"x":-3,"y":-2.25}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left lower leg":{"rotate":[{"time":0,"angle":-16.25},{"time":0.2333,"angle":-52.21},{"time":0.4,"angle":15.04},{"time":0.4666,"angle":-8.95},{"time":0.5666,"angle":-39.53},{"time":0.7666,"angle":-27.27},{"time":0.9333,"angle":-3.52},{"time":1.0666,"angle":-61.92},{"time":1.3666,"angle":-16.25}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left foot":{"rotate":[{"time":0,"angle":0.33},{"time":0.2333,"angle":6.2},{"time":0.3333,"angle":14.73},{"time":0.4,"angle":-15.54},{"time":0.4333,"angle":-21.2},{"time":0.5666,"angle":-7.55},{"time":0.7666,"angle":-0.67},{"time":0.9333,"angle":-0.58},{"time":1.0666,"angle":14.64},{"time":1.3666,"angle":0.33}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right upper leg":{"rotate":[{"time":0,"angle":25.97},{"time":0.2333,"angle":46.43},{"time":0.3333,"angle":22.61},{"time":0.4,"angle":2.13},{"time":0.4666,"angle":0.04,"curve":[0,0,0.637,0.98]},{"time":0.6,"angle":65.55},{"time":0.7666,"angle":64.93},{"time":0.9333,"angle":41.08},{"time":1.0666,"angle":66.25},{"time":1.3666,"angle":25.97}],"translate":[{"time":0,"x":5.74,"y":0.61},{"time":0.2333,"x":4.79,"y":1.79},{"time":0.3333,"x":6.05,"y":-4.55},{"time":0.9333,"x":4.79,"y":1.79,"curve":"stepped"},{"time":1.0666,"x":4.79,"y":1.79},{"time":1.3666,"x":5.74,"y":0.61}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right lower leg":{"rotate":[{"time":0,"angle":-27.46},{"time":0.2333,"angle":-64.03},{"time":0.4,"angle":-48.36},{"time":0.5666,"angle":-76.86},{"time":0.7666,"angle":-26.89},{"time":0.9,"angle":-18.97},{"time":0.9333,"angle":-14.18},{"time":1.0666,"angle":-80.45},{"time":1.3666,"angle":-27.46}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right foot":{"rotate":[{"time":0,"angle":1.08},{"time":0.2333,"angle":16.02},{"time":0.3,"angle":12.94},{"time":0.3333,"angle":15.16},{"time":0.4,"angle":-14.7},{"time":0.4333,"angle":-12.85},{"time":0.4666,"angle":-19.18},{"time":0.5666,"angle":-15.82},{"time":0.6,"angle":-3.59},{"time":0.7666,"angle":-3.56},{"time":0.9333,"angle":1.86},{"time":1.0666,"angle":16.02},{"time":1.3666,"angle":1.08}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"torso":{"rotate":[{"time":0,"angle":-13.35},{"time":0.2333,"angle":-48.95},{"time":0.4333,"angle":-35.77},{"time":0.6,"angle":-4.59},{"time":0.7666,"angle":14.61},{"time":0.9333,"angle":15.74},{"time":1.0666,"angle":-32.44},{"time":1.3666,"angle":-13.35}],"translate":[{"time":0,"x":-3.67,"y":1.68,"curve":"stepped"},{"time":0.9333,"x":-3.67,"y":1.68,"curve":"stepped"},{"time":1.3666,"x":-3.67,"y":1.68}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"neck":{"rotate":[{"time":0,"angle":12.78},{"time":0.2333,"angle":16.46},{"time":0.4,"angle":26.49},{"time":0.6,"angle":15.51},{"time":0.7666,"angle":1.34},{"time":0.9333,"angle":2.35},{"time":1.0666,"angle":6.08},{"time":1.3,"angle":21.23},{"time":1.3666,"angle":12.78}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"head":{"rotate":[{"time":0,"angle":5.19},{"time":0.2333,"angle":20.27},{"time":0.4,"angle":15.27},{"time":0.6,"angle":-24.69},{"time":0.7666,"angle":-11.02},{"time":0.9333,"angle":-24.38},{"time":1.0666,"angle":11.99},{"time":1.3,"angle":4.86},{"time":1.3666,"angle":5.19}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left shoulder":{"rotate":[{"time":0,"angle":0.05,"curve":[0,0,0.62,1]},{"time":0.2333,"angle":279.66,"curve":[0.218,0.67,0.66,0.99]},{"time":0.5,"angle":62.27,"curve":[0.462,0,0.764,0.58]},{"time":0.9333,"angle":28.91},{"time":1.0666,"angle":-8.62},{"time":1.1666,"angle":-18.43},{"time":1.3666,"angle":0.05}],"translate":[{"time":0,"x":-1.76,"y":0.56,"curve":"stepped"},{"time":0.9333,"x":-1.76,"y":0.56,"curve":"stepped"},{"time":1.3666,"x":-1.76,"y":0.56}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left hand":{"rotate":[{"time":0,"angle":11.58,"curve":"stepped"},{"time":0.9333,"angle":11.58,"curve":"stepped"},{"time":1.3666,"angle":11.58}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left arm":{"rotate":[{"time":0,"angle":0.51},{"time":0.4333,"angle":12.82},{"time":0.6,"angle":47.55},{"time":0.9333,"angle":12.82},{"time":1.1666,"angle":-6.5},{"time":1.3666,"angle":0.51}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right shoulder":{"rotate":[{"time":0,"angle":43.82,"curve":[0,0,0.62,1]},{"time":0.2333,"angle":-8.74,"curve":[0.304,0.58,0.709,0.97]},{"time":0.5333,"angle":-208.02,"curve":[0.462,0,0.764,0.58]},{"time":0.9333,"angle":-246.72},{"time":1.0666,"angle":-307.13},{"time":1.1666,"angle":37.15},{"time":1.3666,"angle":43.82}],"translate":[{"time":0,"x":-7.84,"y":7.19,"curve":"stepped"},{"time":0.9333,"x":-7.84,"y":7.19,"curve":"stepped"},{"time":1.3666,"x":-7.84,"y":7.19}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right arm":{"rotate":[{"time":0,"angle":-4.02},{"time":0.6,"angle":17.5},{"time":0.9333,"angle":-4.02},{"time":1.1666,"angle":-16.72},{"time":1.3666,"angle":-4.02}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right hand":{"rotate":[{"time":0,"angle":22.92,"curve":"stepped"},{"time":0.9333,"angle":22.92,"curve":"stepped"},{"time":1.3666,"angle":22.92}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"root":{"rotate":[{"time":0,"angle":0},{"time":0.4333,"angle":-14.52},{"time":0.8,"angle":9.86},{"time":1.3666,"angle":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]}}},"walk":{"bones":{"left upper leg":{"rotate":[{"time":0,"angle":-26.55},{"time":0.1333,"angle":-8.78},{"time":0.2666,"angle":9.51},{"time":0.4,"angle":30.74},{"time":0.5333,"angle":25.33},{"time":0.6666,"angle":26.11},{"time":0.8,"angle":-7.7},{"time":0.9333,"angle":-21.19},{"time":1.0666,"angle":-26.55}],"translate":[{"time":0,"x":-3,"y":-2.25},{"time":0.4,"x":-2.18,"y":-2.25},{"time":1.0666,"x":-3,"y":-2.25}]},"right upper leg":{"rotate":[{"time":0,"angle":42.45},{"time":0.1333,"angle":52.1},{"time":0.2666,"angle":5.96},{"time":0.5333,"angle":-16.93},{"time":0.6666,"angle":1.89},{"time":0.8,"angle":28.06,"curve":[0.462,0.11,1,1]},{"time":0.9333,"angle":58.68,"curve":[0.5,0.02,1,1]},{"time":1.0666,"angle":42.45}],"translate":[{"time":0,"x":8.11,"y":-2.36},{"time":0.1333,"x":10.03,"y":-2.56},{"time":0.4,"x":2.76,"y":-2.97},{"time":0.5333,"x":2.76,"y":-2.81},{"time":0.9333,"x":8.67,"y":-2.54},{"time":1.0666,"x":8.11,"y":-2.36}]},"left lower leg":{"rotate":[{"time":0,"angle":-10.21},{"time":0.1333,"angle":-55.64},{"time":0.2666,"angle":-68.12},{"time":0.5333,"angle":5.11},{"time":0.6666,"angle":-28.29},{"time":0.8,"angle":4.08},{"time":0.9333,"angle":3.53},{"time":1.0666,"angle":-10.21}]},"left foot":{"rotate":[{"time":0,"angle":-3.69},{"time":0.1333,"angle":-10.42},{"time":0.2666,"angle":-17.14},{"time":0.4,"angle":-2.83},{"time":0.5333,"angle":-3.87},{"time":0.6666,"angle":2.78},{"time":0.8,"angle":1.68},{"time":0.9333,"angle":-8.54},{"time":1.0666,"angle":-3.69}]},"right shoulder":{"rotate":[{"time":0,"angle":20.89,"curve":[0.264,0,0.75,1]},{"time":0.1333,"angle":3.72,"curve":[0.272,0,0.841,1]},{"time":0.6666,"angle":-278.28},{"time":1.0666,"angle":20.89}],"translate":[{"time":0,"x":-7.84,"y":7.19},{"time":0.1333,"x":-6.36,"y":6.42},{"time":0.6666,"x":-11.07,"y":5.25},{"time":1.0666,"x":-7.84,"y":7.19}]},"right arm":{"rotate":[{"time":0,"angle":-4.02,"curve":[0.267,0,0.804,0.99]},{"time":0.1333,"angle":-13.99,"curve":[0.341,0,1,1]},{"time":0.6666,"angle":36.54,"curve":[0.307,0,0.787,0.99]},{"time":1.0666,"angle":-4.02}]},"right hand":{"rotate":[{"time":0,"angle":22.92},{"time":0.4,"angle":-8.97},{"time":0.6666,"angle":0.51},{"time":1.0666,"angle":22.92}]},"left shoulder":{"rotate":[{"time":0,"angle":-1.47},{"time":0.1333,"angle":13.6},{"time":0.6666,"angle":280.74},{"time":1.0666,"angle":-1.47}],"translate":[{"time":0,"x":-1.76,"y":0.56},{"time":0.6666,"x":-2.47,"y":8.14},{"time":1.0666,"x":-1.76,"y":0.56}]},"left hand":{"rotate":[{"time":0,"angle":11.58,"curve":[0.169,0.37,0.632,1.55]},{"time":0.1333,"angle":28.13,"curve":[0.692,0,0.692,0.99]},{"time":0.6666,"angle":-27.42,"curve":[0.117,0.41,0.738,1.76]},{"time":0.8,"angle":-36.32},{"time":1.0666,"angle":11.58}]},"left arm":{"rotate":[{"time":0,"angle":-8.27},{"time":0.1333,"angle":18.43},{"time":0.6666,"angle":0.88},{"time":1.0666,"angle":-8.27}]},"torso":{"rotate":[{"time":0,"angle":-10.28},{"time":0.1333,"angle":-15.38,"curve":[0.545,0,1,1]},{"time":0.4,"angle":-9.78,"curve":[0.58,0.17,1,1]},{"time":0.6666,"angle":-15.75},{"time":0.9333,"angle":-7.06},{"time":1.0666,"angle":-10.28}],"translate":[{"time":0,"x":-3.67,"y":1.68},{"time":0.1333,"x":-3.67,"y":0.68},{"time":0.4,"x":-3.67,"y":1.97},{"time":0.6666,"x":-3.67,"y":-0.14},{"time":1.0666,"x":-3.67,"y":1.68}]},"right foot":{"rotate":[{"time":0,"angle":-5.25},{"time":0.2666,"angle":-4.08},{"time":0.4,"angle":-6.45},{"time":0.5333,"angle":-5.39},{"time":0.8,"angle":-11.68},{"time":0.9333,"angle":0.46},{"time":1.0666,"angle":-5.25}]},"right lower leg":{"rotate":[{"time":0,"angle":-3.39},{"time":0.1333,"angle":-45.53},{"time":0.2666,"angle":-2.59},{"time":0.5333,"angle":-19.53},{"time":0.6666,"angle":-64.8},{"time":0.8,"angle":-82.56,"curve":[0.557,0.18,1,1]},{"time":1.0666,"angle":-3.39}]},"hip":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0},{"time":0.1333,"x":0,"y":-7.61,"curve":[0.272,0.86,1,1]},{"time":0.4,"x":0,"y":8.7},{"time":0.5333,"x":0,"y":-0.41},{"time":0.6666,"x":0,"y":-7.05,"curve":[0.235,0.89,1,1]},{"time":0.8,"x":0,"y":2.92},{"time":0.9333,"x":0,"y":6.78},{"time":1.0666,"x":0,"y":0}]},"neck":{"rotate":[{"time":0,"angle":3.6},{"time":0.1333,"angle":17.49},{"time":0.2666,"angle":6.1},{"time":0.4,"angle":3.45},{"time":0.5333,"angle":5.17},{"time":0.6666,"angle":18.36},{"time":0.8,"angle":6.09},{"time":0.9333,"angle":2.28},{"time":1.0666,"angle":3.6}]},"head":{"rotate":[{"time":0,"angle":3.6,"curve":[0,0,0.704,1.61]},{"time":0.1666,"angle":-0.2},{"time":0.2666,"angle":6.1},{"time":0.4,"angle":3.45},{"time":0.5333,"angle":5.17,"curve":[0,0,0.704,1.61]},{"time":0.7,"angle":1.1},{"time":0.8,"angle":6.09},{"time":0.9333,"angle":2.28},{"time":1.0666,"angle":3.6}]}}}}} \ No newline at end of file +{"bones":[{"name":"root"},{"name":"hip","parent":"root","x":0.64,"y":114.41},{"name":"left upper leg","parent":"hip","length":50.39,"x":14.45,"y":2.81,"rotation":-89.09},{"name":"pelvis","parent":"hip","x":1.41,"y":-6.57},{"name":"right upper leg","parent":"hip","length":45.76,"x":-18.27,"rotation":-101.13},{"name":"torso","parent":"hip","length":85.82,"x":-6.42,"y":1.97,"rotation":94.95},{"name":"left lower leg","parent":"left upper leg","length":56.45,"x":51.78,"y":3.46,"rotation":-16.65},{"name":"left shoulder","parent":"torso","length":44.19,"x":78.96,"y":-15.75,"rotation":-156.96},{"name":"neck","parent":"torso","length":18.38,"x":83.64,"y":-1.78,"rotation":0.9},{"name":"right lower leg","parent":"right upper leg","length":58.52,"x":50.21,"y":0.6,"rotation":-10.7},{"name":"right shoulder","parent":"torso","length":49.95,"x":81.9,"y":6.79,"rotation":130.6},{"name":"head","parent":"neck","length":68.28,"x":19.09,"y":6.97,"rotation":-8.94},{"name":"left arm","parent":"left shoulder","length":35.62,"x":44.19,"y":-0.01,"rotation":28.16},{"name":"left foot","parent":"left lower leg","length":46.5,"x":64.02,"y":-8.67,"rotation":102.43},{"name":"right arm","parent":"right shoulder","length":36.74,"x":49.95,"y":-0.12,"rotation":40.12},{"name":"right foot","parent":"right lower leg","length":45.45,"x":64.88,"y":0.04,"rotation":110.3},{"name":"left hand","parent":"left arm","length":11.52,"x":35.62,"y":0.07,"rotation":2.7},{"name":"right hand","parent":"right arm","length":15.32,"x":36.9,"y":0.34,"rotation":2.35}],"slots":[{"name":"left shoulder","bone":"left shoulder","attachment":"left-shoulder"},{"name":"left arm","bone":"left arm","attachment":"left-arm"},{"name":"left hand","bone":"left hand","attachment":"left-hand"},{"name":"left foot","bone":"left foot","attachment":"left-foot"},{"name":"left lower leg","bone":"left lower leg","attachment":"left-lower-leg"},{"name":"left upper leg","bone":"left upper leg","attachment":"left-upper-leg"},{"name":"pelvis","bone":"pelvis","attachment":"pelvis"},{"name":"right foot","bone":"right foot","attachment":"right-foot"},{"name":"right lower leg","bone":"right lower leg","attachment":"right-lower-leg"},{"name":"right upper leg","bone":"right upper leg","attachment":"right-upper-leg"},{"name":"torso","bone":"torso","attachment":"torso"},{"name":"neck","bone":"neck","attachment":"neck"},{"name":"head","bone":"head","attachment":"head"},{"name":"eyes","bone":"head","attachment":"eyes"},{"name":"right shoulder","bone":"right shoulder","attachment":"right-shoulder","additive":true},{"name":"right arm","bone":"right arm","attachment":"right-arm"},{"name":"right hand","bone":"right hand","attachment":"right-hand"},{"name":"bb-head","bone":"head","attachment":"bb-head"}],"skins":{"default":{"bb-head":{"bb-head":{"type":"boundingbox","vertices":[55.69696,-44.60648,8.2226715,-47.609646,-11.244263,-32.942703,-0.05206299,35.835804,61.018433,43.227512,90.35846,-16.054127,115.41275,-32.817406,78.29431,-56.05409]}},"eyes":{"eyes":{"x":28.94,"y":-32.92,"rotation":-86.9,"width":34,"height":27},"eyes-closed":{"x":28.77,"y":-32.86,"rotation":-86.9,"width":34,"height":27}},"head":{"head":{"x":53.94,"y":-5.75,"rotation":-86.9,"width":121,"height":132}},"left arm":{"left-arm":{"x":15.11,"y":-0.44,"rotation":33.84,"width":35,"height":29}},"left foot":{"left-foot":{"x":24.35,"y":8.88,"rotation":3.32,"width":65,"height":30}},"left hand":{"left-hand":{"x":0.75,"y":1.86,"rotation":31.14,"width":35,"height":38}},"left lower leg":{"left-lower-leg":{"x":24.55,"y":-1.92,"rotation":105.75,"width":49,"height":64}},"left shoulder":{"left-shoulder":{"x":23.74,"y":0.11,"rotation":62.01,"width":34,"height":53}},"left upper leg":{"left-upper-leg":{"x":26.12,"y":-1.85,"rotation":89.09,"width":33,"height":67}},"neck":{"neck":{"x":9.42,"y":-3.66,"rotation":-100.15,"width":34,"height":28}},"pelvis":{"pelvis":{"x":-4.83,"y":10.62,"width":63,"height":47}},"right arm":{"right-arm":{"x":18.34,"y":-2.64,"rotation":94.32,"width":21,"height":45}},"right foot":{"right-foot":{"x":19.02,"y":8.47,"rotation":1.52,"width":67,"height":30}},"right hand":{"right-hand":{"x":6.82,"y":1.25,"rotation":91.96,"width":32,"height":32}},"right lower leg":{"right-lower-leg":{"x":23.28,"y":-2.59,"rotation":111.83,"width":51,"height":64}},"right shoulder":{"right-shoulder":{"x":25.86,"y":0.03,"rotation":134.44,"width":52,"height":51}},"right upper leg":{"right-upper-leg":{"x":23.03,"y":0.25,"rotation":101.13,"width":44,"height":70}},"torso":{"torso":{"x":44.57,"y":-7.08,"rotation":-94.95,"width":68,"height":92}}}},"events":{"behind":{},"headAttach":{},"headPop":{}},"animations":{"drawOrder":{"bones":{"head":{"rotate":[{"time":0,"angle":0},{"time":0.4827,"angle":-11.07,"curve":"stepped"},{"time":0.8965,"angle":-11.07},{"time":1.3103,"angle":1.38},{"time":1.7931,"angle":12.91},{"time":2.1379,"angle":1.24},{"time":2.6206,"angle":-16.12,"curve":"stepped"},{"time":3.3103,"angle":-16.12},{"time":3.6551,"angle":1.31},{"time":4,"angle":359.99}],"translate":[{"time":0,"x":0,"y":0,"curve":[0.19,0.4,0.586,0.75]},{"time":0.2758,"x":57.88,"y":-35.72,"curve":[0.39,0.54,0.632,0.72]},{"time":0.4827,"x":87.26,"y":-87.89,"curve":[0.325,0.23,0.587,0.36]},{"time":0.6896,"x":28.89,"y":-114.62,"curve":[0.383,0.23,0.736,0.55]},{"time":0.8965,"x":-76.58,"y":-124.98,"curve":[0.129,0.21,0.547,0.64]},{"time":1.1034,"x":-154.37,"y":-77.13,"curve":[0.354,0.48,0.729,0.9]},{"time":1.3103,"x":-181.02,"y":18.56,"curve":[0.063,0.15,0.52,0.62]},{"time":1.5862,"x":-150.38,"y":128.67,"curve":[0.381,0.54,0.778,1]},{"time":1.7931,"x":-112.08,"y":146.28,"curve":[0.242,0,0.626,0.45]},{"time":1.931,"x":-63.7,"y":111.22,"curve":[0.398,0.35,0.786,0.76]},{"time":2.1379,"x":-48.94,"y":-1.55,"curve":[0.188,0.21,0.575,0.61]},{"time":2.3448,"x":-91.69,"y":-91.93,"curve":[0.362,0.51,0.766,1]},{"time":2.6206,"x":-142.79,"y":-126.83,"curve":[0.227,0.34,0.593,0.75]},{"time":2.7586,"x":-176.7,"y":-98.32,"curve":[0.26,0.4,0.612,0.71]},{"time":2.8965,"x":-163.95,"y":-24.04,"curve":[0.338,0.37,0.676,0.71]},{"time":2.9655,"x":-150.17,"y":10.71,"curve":[0.387,0.61,0.741,1]},{"time":3.1034,"x":-102.44,"y":45.92,"curve":[0.31,0.24,0.648,0.58]},{"time":3.2413,"x":-53.99,"y":70.39,"curve":[0.325,0.29,0.663,0.63]},{"time":3.3793,"x":1.88,"y":55.54,"curve":[0.387,0.33,0.769,0.73]},{"time":3.5862,"x":34.26,"y":36.13,"curve":[0.206,0.28,0.596,0.67]},{"time":3.7931,"x":23.94,"y":1.01,"curve":[0.373,0.56,0.759,1]},{"time":4,"x":0,"y":0}],"scale":[{"time":0.8275,"x":1,"y":1},{"time":1.3103,"x":0.742,"y":0.742},{"time":1.7931,"x":1,"y":1},{"time":2.1379,"x":1.502,"y":1.502},{"time":2.6206,"x":1,"y":1},{"time":2.9655,"x":0.707,"y":0.707},{"time":3.3793,"x":1,"y":1}]}},"events":[{"time":0,"name":"headPop","string":"pop.wav"},{"time":1.3103,"name":"behind"},{"time":2.9655,"name":"behind"},{"time":4,"name":"headAttach","string":"attach.wav"}],"draworder":[{"time":0.6206,"offsets":[{"slot":"head","offset":-12},{"slot":"eyes","offset":-12}]},{"time":1.7931,"offsets":[{"slot":"head","offset":3},{"slot":"eyes","offset":3}]},{"time":2.6206,"offsets":[{"slot":"head","offset":-12},{"slot":"eyes","offset":-12}]},{"time":3.5862,"offsets":[]}]},"jump":{"bones":{"hip":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":0.9333,"angle":0,"curve":"stepped"},{"time":1.3666,"angle":0}],"translate":[{"time":0,"x":-11.57,"y":-3},{"time":0.2333,"x":-16.2,"y":-19.43},{"time":0.3333,"x":7.66,"y":-8.48,"curve":[0.057,0.06,0.712,1]},{"time":0.3666,"x":15.38,"y":5.01},{"time":0.4666,"x":-7.84,"y":57.22},{"time":0.6,"x":-10.81,"y":96.34,"curve":[0.241,0,1,1]},{"time":0.7333,"x":-7.01,"y":54.7},{"time":0.8,"x":-10.58,"y":32.2},{"time":0.9333,"x":-31.99,"y":0.45},{"time":1.0666,"x":-12.48,"y":-29.47},{"time":1.3666,"x":-11.57,"y":-3}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left upper leg":{"rotate":[{"time":0,"angle":17.13},{"time":0.2333,"angle":44.35},{"time":0.3333,"angle":16.46},{"time":0.4,"angle":-9.88},{"time":0.4666,"angle":-11.42},{"time":0.5666,"angle":23.46},{"time":0.7666,"angle":71.82},{"time":0.9333,"angle":65.53},{"time":1.0666,"angle":51.01},{"time":1.3666,"angle":17.13}],"translate":[{"time":0,"x":-3,"y":-2.25,"curve":"stepped"},{"time":0.9333,"x":-3,"y":-2.25,"curve":"stepped"},{"time":1.3666,"x":-3,"y":-2.25}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left lower leg":{"rotate":[{"time":0,"angle":-16.25},{"time":0.2333,"angle":-52.21},{"time":0.4,"angle":15.04},{"time":0.4666,"angle":-8.95},{"time":0.5666,"angle":-39.53},{"time":0.7666,"angle":-27.27},{"time":0.9333,"angle":-3.52},{"time":1.0666,"angle":-61.92},{"time":1.3666,"angle":-16.25}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left foot":{"rotate":[{"time":0,"angle":0.33},{"time":0.2333,"angle":6.2},{"time":0.3333,"angle":14.73},{"time":0.4,"angle":-15.54},{"time":0.4333,"angle":-21.2},{"time":0.5666,"angle":-7.55},{"time":0.7666,"angle":-0.67},{"time":0.9333,"angle":-0.58},{"time":1.0666,"angle":14.64},{"time":1.3666,"angle":0.33}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right upper leg":{"rotate":[{"time":0,"angle":25.97},{"time":0.2333,"angle":46.43},{"time":0.3333,"angle":22.61},{"time":0.4,"angle":2.13},{"time":0.4666,"angle":0.04,"curve":[0,0,0.637,0.98]},{"time":0.6,"angle":65.55},{"time":0.7666,"angle":64.93},{"time":0.9333,"angle":41.08},{"time":1.0666,"angle":66.25},{"time":1.3666,"angle":25.97}],"translate":[{"time":0,"x":5.74,"y":0.61},{"time":0.2333,"x":4.79,"y":1.79},{"time":0.3333,"x":6.05,"y":-4.55},{"time":0.9333,"x":4.79,"y":1.79,"curve":"stepped"},{"time":1.0666,"x":4.79,"y":1.79},{"time":1.3666,"x":5.74,"y":0.61}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right lower leg":{"rotate":[{"time":0,"angle":-27.46},{"time":0.2333,"angle":-64.03},{"time":0.4,"angle":-48.36},{"time":0.5666,"angle":-76.86},{"time":0.7666,"angle":-26.89},{"time":0.9,"angle":-18.97},{"time":0.9333,"angle":-14.18},{"time":1.0666,"angle":-80.45},{"time":1.3666,"angle":-27.46}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right foot":{"rotate":[{"time":0,"angle":1.08},{"time":0.2333,"angle":16.02},{"time":0.3,"angle":12.94},{"time":0.3333,"angle":15.16},{"time":0.4,"angle":-14.7},{"time":0.4333,"angle":-12.85},{"time":0.4666,"angle":-19.18},{"time":0.5666,"angle":-15.82},{"time":0.6,"angle":-3.59},{"time":0.7666,"angle":-3.56},{"time":0.9333,"angle":1.86},{"time":1.0666,"angle":16.02},{"time":1.3666,"angle":1.08}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"torso":{"rotate":[{"time":0,"angle":-13.35},{"time":0.2333,"angle":-48.95},{"time":0.4333,"angle":-35.77},{"time":0.6,"angle":-4.59},{"time":0.7666,"angle":14.61},{"time":0.9333,"angle":15.74},{"time":1.0666,"angle":-32.44},{"time":1.3666,"angle":-13.35}],"translate":[{"time":0,"x":-3.67,"y":1.68,"curve":"stepped"},{"time":0.9333,"x":-3.67,"y":1.68,"curve":"stepped"},{"time":1.3666,"x":-3.67,"y":1.68}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"neck":{"rotate":[{"time":0,"angle":12.78},{"time":0.2333,"angle":16.46},{"time":0.4,"angle":26.49},{"time":0.6,"angle":15.51},{"time":0.7666,"angle":1.34},{"time":0.9333,"angle":2.35},{"time":1.0666,"angle":6.08},{"time":1.3,"angle":21.23},{"time":1.3666,"angle":12.78}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"head":{"rotate":[{"time":0,"angle":5.19},{"time":0.2333,"angle":20.27},{"time":0.4,"angle":15.27},{"time":0.6,"angle":-24.69},{"time":0.7666,"angle":-11.02},{"time":0.9333,"angle":-24.38},{"time":1.0666,"angle":11.99},{"time":1.3,"angle":4.86},{"time":1.3666,"angle":5.19}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left shoulder":{"rotate":[{"time":0,"angle":0.05,"curve":[0,0,0.62,1]},{"time":0.2333,"angle":279.66,"curve":[0.218,0.67,0.66,0.99]},{"time":0.5,"angle":62.27,"curve":[0.462,0,0.764,0.58]},{"time":0.9333,"angle":28.91},{"time":1.0666,"angle":-8.62},{"time":1.1666,"angle":-18.43},{"time":1.3666,"angle":0.05}],"translate":[{"time":0,"x":-1.76,"y":0.56,"curve":"stepped"},{"time":0.9333,"x":-1.76,"y":0.56,"curve":"stepped"},{"time":1.3666,"x":-1.76,"y":0.56}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left hand":{"rotate":[{"time":0,"angle":11.58,"curve":"stepped"},{"time":0.9333,"angle":11.58,"curve":"stepped"},{"time":1.3666,"angle":11.58}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"left arm":{"rotate":[{"time":0,"angle":0.51},{"time":0.4333,"angle":12.82},{"time":0.6,"angle":47.55},{"time":0.9333,"angle":12.82},{"time":1.1666,"angle":-6.5},{"time":1.3666,"angle":0.51}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right shoulder":{"rotate":[{"time":0,"angle":43.82,"curve":[0,0,0.62,1]},{"time":0.2333,"angle":-8.74,"curve":[0.304,0.58,0.709,0.97]},{"time":0.5333,"angle":-208.02,"curve":[0.462,0,0.764,0.58]},{"time":0.9333,"angle":-246.72},{"time":1.0666,"angle":-307.13},{"time":1.1666,"angle":37.15},{"time":1.3666,"angle":43.82}],"translate":[{"time":0,"x":-7.84,"y":7.19,"curve":"stepped"},{"time":0.9333,"x":-7.84,"y":7.19,"curve":"stepped"},{"time":1.3666,"x":-7.84,"y":7.19}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right arm":{"rotate":[{"time":0,"angle":-4.02},{"time":0.6,"angle":17.5},{"time":0.9333,"angle":-4.02},{"time":1.1666,"angle":-16.72},{"time":1.3666,"angle":-4.02}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"right hand":{"rotate":[{"time":0,"angle":22.92,"curve":"stepped"},{"time":0.9333,"angle":22.92,"curve":"stepped"},{"time":1.3666,"angle":22.92}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.9333,"x":0,"y":0,"curve":"stepped"},{"time":1.3666,"x":0,"y":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":0.9333,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]},"root":{"rotate":[{"time":0,"angle":0},{"time":0.4333,"angle":-14.52},{"time":0.8,"angle":9.86},{"time":1.3666,"angle":0}],"scale":[{"time":0,"x":1,"y":1,"curve":"stepped"},{"time":1.3666,"x":1,"y":1}]}}},"walk":{"bones":{"left upper leg":{"rotate":[{"time":0,"angle":-26.55},{"time":0.1333,"angle":-8.78},{"time":0.2666,"angle":9.51},{"time":0.4,"angle":30.74},{"time":0.5333,"angle":25.33},{"time":0.6666,"angle":26.11},{"time":0.8,"angle":-7.7},{"time":0.9333,"angle":-21.19},{"time":1.0666,"angle":-26.55}],"translate":[{"time":0,"x":-3,"y":-2.25},{"time":0.4,"x":-2.18,"y":-2.25},{"time":1.0666,"x":-3,"y":-2.25}]},"right upper leg":{"rotate":[{"time":0,"angle":42.45},{"time":0.1333,"angle":52.1},{"time":0.2666,"angle":5.96},{"time":0.5333,"angle":-16.93},{"time":0.6666,"angle":1.89},{"time":0.8,"angle":28.06,"curve":[0.462,0.11,1,1]},{"time":0.9333,"angle":58.68,"curve":[0.5,0.02,1,1]},{"time":1.0666,"angle":42.45}],"translate":[{"time":0,"x":8.11,"y":-2.36},{"time":0.1333,"x":10.03,"y":-2.56},{"time":0.4,"x":2.76,"y":-2.97},{"time":0.5333,"x":2.76,"y":-2.81},{"time":0.9333,"x":8.67,"y":-2.54},{"time":1.0666,"x":8.11,"y":-2.36}]},"left lower leg":{"rotate":[{"time":0,"angle":-10.21},{"time":0.1333,"angle":-55.64},{"time":0.2666,"angle":-68.12},{"time":0.5333,"angle":5.11},{"time":0.6666,"angle":-28.29},{"time":0.8,"angle":4.08},{"time":0.9333,"angle":3.53},{"time":1.0666,"angle":-10.21}]},"left foot":{"rotate":[{"time":0,"angle":-3.69},{"time":0.1333,"angle":-10.42},{"time":0.2666,"angle":-17.14},{"time":0.4,"angle":-2.83},{"time":0.5333,"angle":-3.87},{"time":0.6666,"angle":2.78},{"time":0.8,"angle":1.68},{"time":0.9333,"angle":-8.54},{"time":1.0666,"angle":-3.69}]},"right shoulder":{"rotate":[{"time":0,"angle":20.89,"curve":[0.264,0,0.75,1]},{"time":0.1333,"angle":3.72,"curve":[0.272,0,0.841,1]},{"time":0.6666,"angle":-278.28},{"time":1.0666,"angle":20.89}],"translate":[{"time":0,"x":-7.84,"y":7.19},{"time":0.1333,"x":-6.36,"y":6.42},{"time":0.6666,"x":-11.07,"y":5.25},{"time":1.0666,"x":-7.84,"y":7.19}]},"right arm":{"rotate":[{"time":0,"angle":-4.02,"curve":[0.267,0,0.804,0.99]},{"time":0.1333,"angle":-13.99,"curve":[0.341,0,1,1]},{"time":0.6666,"angle":36.54,"curve":[0.307,0,0.787,0.99]},{"time":1.0666,"angle":-4.02}]},"right hand":{"rotate":[{"time":0,"angle":22.92},{"time":0.4,"angle":-8.97},{"time":0.6666,"angle":0.51},{"time":1.0666,"angle":22.92}]},"left shoulder":{"rotate":[{"time":0,"angle":-1.47},{"time":0.1333,"angle":13.6},{"time":0.6666,"angle":280.74},{"time":1.0666,"angle":-1.47}],"translate":[{"time":0,"x":-1.76,"y":0.56},{"time":0.6666,"x":-2.47,"y":8.14},{"time":1.0666,"x":-1.76,"y":0.56}]},"left hand":{"rotate":[{"time":0,"angle":11.58,"curve":[0.169,0.37,0.632,1.55]},{"time":0.1333,"angle":28.13,"curve":[0.692,0,0.692,0.99]},{"time":0.6666,"angle":-27.42,"curve":[0.117,0.41,0.738,1.76]},{"time":0.8,"angle":-36.32},{"time":1.0666,"angle":11.58}]},"left arm":{"rotate":[{"time":0,"angle":-8.27},{"time":0.1333,"angle":18.43},{"time":0.6666,"angle":0.88},{"time":1.0666,"angle":-8.27}]},"torso":{"rotate":[{"time":0,"angle":-10.28},{"time":0.1333,"angle":-15.38,"curve":[0.545,0,1,1]},{"time":0.4,"angle":-9.78,"curve":[0.58,0.17,1,1]},{"time":0.6666,"angle":-15.75},{"time":0.9333,"angle":-7.06},{"time":1.0666,"angle":-10.28}],"translate":[{"time":0,"x":-3.67,"y":1.68},{"time":0.1333,"x":-3.67,"y":0.68},{"time":0.4,"x":-3.67,"y":1.97},{"time":0.6666,"x":-3.67,"y":-0.14},{"time":1.0666,"x":-3.67,"y":1.68}]},"right foot":{"rotate":[{"time":0,"angle":-5.25},{"time":0.2666,"angle":-4.08},{"time":0.4,"angle":-6.45},{"time":0.5333,"angle":-5.39},{"time":0.8,"angle":-11.68},{"time":0.9333,"angle":0.46},{"time":1.0666,"angle":-5.25}]},"right lower leg":{"rotate":[{"time":0,"angle":-3.39},{"time":0.1333,"angle":-45.53},{"time":0.2666,"angle":-2.59},{"time":0.5333,"angle":-19.53},{"time":0.6666,"angle":-64.8},{"time":0.8,"angle":-82.56,"curve":[0.557,0.18,1,1]},{"time":1.0666,"angle":-3.39}]},"hip":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0},{"time":0.1333,"x":0,"y":-7.61,"curve":[0.272,0.86,1,1]},{"time":0.4,"x":0,"y":8.7},{"time":0.5333,"x":0,"y":-0.41},{"time":0.6666,"x":0,"y":-7.05,"curve":[0.235,0.89,1,1]},{"time":0.8,"x":0,"y":2.92},{"time":0.9333,"x":0,"y":6.78},{"time":1.0666,"x":0,"y":0}]},"neck":{"rotate":[{"time":0,"angle":3.6},{"time":0.1333,"angle":17.49},{"time":0.2666,"angle":6.1},{"time":0.4,"angle":3.45},{"time":0.5333,"angle":5.17},{"time":0.6666,"angle":18.36},{"time":0.8,"angle":6.09},{"time":0.9333,"angle":2.28},{"time":1.0666,"angle":3.6}]},"head":{"rotate":[{"time":0,"angle":3.6,"curve":[0,0,0.704,1.61]},{"time":0.1666,"angle":-0.2},{"time":0.2666,"angle":6.1},{"time":0.4,"angle":3.45},{"time":0.5333,"angle":5.17,"curve":[0,0,0.704,1.61]},{"time":0.7,"angle":1.1},{"time":0.8,"angle":6.09},{"time":0.9333,"angle":2.28},{"time":1.0666,"angle":3.6}]}}}}} \ No newline at end of file diff --git a/spine-xna/example/src/ExampleGame.cs b/spine-xna/example/src/ExampleGame.cs index 049fb8d6c..4520bf49d 100644 --- a/spine-xna/example/src/ExampleGame.cs +++ b/spine-xna/example/src/ExampleGame.cs @@ -40,9 +40,13 @@ namespace Spine { GraphicsDeviceManager graphics; SkeletonRenderer skeletonRenderer; Skeleton skeleton; + Slot headSlot; AnimationState state; + SkeletonBounds bounds = new SkeletonBounds(); public Example () { + IsMouseVisible = true; + graphics = new GraphicsDeviceManager(this); graphics.IsFullScreen = false; graphics.PreferredBackBufferWidth = 640; @@ -74,14 +78,19 @@ namespace Spine { } state = new AnimationState(stateData); - state.SetAnimation("drawOrder", true); - //state.SetAnimation("walk", false); - //state.AddAnimation("jump", false); - //state.AddAnimation("walk", true); + if (true) { + state.SetAnimation("drawOrder", true); + } else { + state.SetAnimation("walk", false); + state.AddAnimation("jump", false); + state.AddAnimation("walk", true); + } skeleton.X = 320; skeleton.Y = 440; skeleton.UpdateWorldTransform(); + + headSlot = skeleton.FindSlot("head"); } protected override void UnloadContent () { @@ -108,6 +117,19 @@ namespace Spine { skeletonRenderer.Draw(skeleton); skeletonRenderer.End(); + bounds.Update(skeleton); + MouseState mouse = Mouse.GetState(); + if (bounds.AabbContainsPoint(mouse.X, mouse.Y)) { + BoundingBoxAttachment hit = bounds.ContainsPoint(mouse.X, mouse.Y); + if (hit != null) { + headSlot.G = 0; + headSlot.B = 0; + } else { + headSlot.G = 1; + headSlot.B = 1; + } + } + base.Draw(gameTime); } } diff --git a/spine-xna/src/SkeletonRenderer.cs b/spine-xna/src/SkeletonRenderer.cs index 105121104..1d76918d3 100644 --- a/spine-xna/src/SkeletonRenderer.cs +++ b/spine-xna/src/SkeletonRenderer.cs @@ -69,8 +69,6 @@ namespace Spine { } public void Draw (Skeleton skeleton) { - Console.WriteLine(); - List drawOrder = skeleton.DrawOrder; for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i];