[csharp][unity] Port of commit cf45806: Added DrawOrderFolderTimeline. Updated example skeleton exports to 4.3.44-beta.

This commit is contained in:
Harald Csaszar 2026-03-16 17:41:19 +01:00
parent e665976598
commit f7ed100aa8
30 changed files with 48863 additions and 48724 deletions

View File

@ -2018,7 +2018,7 @@ namespace Spine {
/// <summary>Changes a skeleton's <see cref="Skeleton.DrawOrder"/>.</summary> /// <summary>Changes a skeleton's <see cref="Skeleton.DrawOrder"/>.</summary>
public class DrawOrderTimeline : Timeline { public class DrawOrderTimeline : Timeline {
static readonly string[] propertyIds = { ((int)Property.DrawOrder).ToString() }; internal static readonly string[] propertyIds = { ((int)Property.DrawOrder).ToString() };
readonly int[][] drawOrders; readonly int[][] drawOrders;
@ -2034,16 +2034,13 @@ namespace Spine {
/// <summary>The draw order for each frame. </summary> /// <summary>The draw order for each frame. </summary>
/// <seealso cref="Timeline.SetFrame(int, float, int[])"/>. /// <seealso cref="Timeline.SetFrame(int, float, int[])"/>.
public int[][] DrawOrders { public int[][] DrawOrders {
get { get { return drawOrders; }
return drawOrders;
}
} }
/// <summary>Sets the time and draw order for the specified frame.</summary> /// <summary>Sets the time and draw order for the specified frame.</summary>
/// <param name="frame">Between 0 and <c>frameCount</c>, inclusive.</param> /// <param name="frame">Between 0 and <c>frameCount</c>, inclusive.</param>
/// <param name="time">The frame time in seconds.</param> /// <param name="time">The frame time in seconds.</param>
/// <param name="drawOrder">For each slot in <see cref="Skeleton.Slots"/>, the index of the slot in the new draw order. May be null to use /// <param name="drawOrder">Ordered <see cref="Skeleton.Slots"/> indices, or null to use setup pose order.</param>
/// setup pose draw order.</param>
public void SetFrame (int frame, float time, int[] drawOrder) { public void SetFrame (int frame, float time, int[] drawOrder) {
frames[frame] = time; frames[frame] = time;
drawOrders[frame] = drawOrder; drawOrders[frame] = drawOrder;
@ -2075,6 +2072,89 @@ namespace Spine {
} }
} }
/// <summary>Changes a subset of a skeleton's <see cref="Skeleton.DrawOrder"/>.</summary>
public class DrawOrderFolderTimeline : Timeline {
private readonly int[] slots;
private readonly bool[] inFolder;
private readonly int[][] drawOrders;
/// <param name="slots"><see cref="Skeleton.Slots"/> indices controlled by this timeline, in setup order.</param>
/// <param name="slotCount">The maximum number of slots in the skeleton.</param>
public DrawOrderFolderTimeline (int frameCount, int[] slots, int slotCount)
: base(frameCount, DrawOrderTimeline.propertyIds) {
this.slots = slots;
drawOrders = new int[frameCount][];
inFolder = new bool[slotCount];
foreach (int i in slots)
inFolder[i] = true;
}
override public int FrameCount {
get { return frames.Length; }
}
/// <summary>The <see cref="Skeleton.Slots"/> indices that this timeline affects, in setup order.</summary>
public int[] Slots {
get { return slots; }
}
/// <summary>The draw order for each frame. </summary>
/// <seealso cref="Timeline.SetFrame(int, float, int[])"/>.
public int[][] DrawOrders {
get { return drawOrders; }
}
/// <summary>Sets the time and draw order for the specified frame.</summary>
/// <param name="frame">Between 0 and <c>frameCount</c>, inclusive.</param>
/// <param name="time">The frame time in seconds.</param>
/// <param name="drawOrder">Ordered <see cref="Skeleton.Slots"/> indices, or null to use setup pose order.</param>
public void SetFrame (int frame, float time, int[] drawOrder) {
frames[frame] = time;
drawOrders[frame] = drawOrder;
}
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> events, float alpha, MixBlend blend,
MixDirection direction, bool appliedPose) {
if (direction == MixDirection.Out) {
if (blend == MixBlend.Setup) setup(skeleton);
} else if (time < frames[0]) {
if (blend == MixBlend.Setup || blend == MixBlend.First) setup(skeleton);
} else {
int[] order = drawOrders[Search(frames, time)];
if (order == null)
setup(skeleton);
else
Apply(skeleton, order);
}
}
private void setup (Skeleton skeleton) {
bool[] inFolder = this.inFolder;
Slot[] drawOrder = skeleton.drawOrder.Items, allSlots = skeleton.slots.Items;
int[] slots = this.slots;
for (int i = 0, found = 0, done = slots.Length; ; i++) {
if (inFolder[drawOrder[i].data.index]) {
drawOrder[i] = allSlots[slots[found]];
if (++found == done) break;
}
}
}
private void Apply (Skeleton skeleton, int[] order) {
bool[] inFolder = this.inFolder;
Slot[] drawOrder = skeleton.drawOrder.Items, allSlots = skeleton.slots.Items;
int[] slots = this.slots;
for (int i = 0, found = 0, done = slots.Length; ; i++) {
if (inFolder[drawOrder[i].data.index]) {
drawOrder[i] = allSlots[slots[order[found]]];
if (++found == done) break;
}
}
}
}
public interface IConstraintTimeline { public interface IConstraintTimeline {
/// <summary> /// <summary>
/// The index of the constraint in <see cref="Skeleton.Constraints"/> that will be changed when this timeline is applied. /// The index of the constraint in <see cref="Skeleton.Constraints"/> that will be changed when this timeline is applied.

View File

@ -919,7 +919,8 @@ namespace Spine {
if (!propertyIds.AddAll(ids)) if (!propertyIds.AddAll(ids))
timelineMode[i] = AnimationState.Subsequent; timelineMode[i] = AnimationState.Subsequent;
else if (to == null || timeline is AttachmentTimeline || timeline is DrawOrderTimeline else if (to == null || timeline is AttachmentTimeline || timeline is DrawOrderTimeline
|| timeline is EventTimeline || !to.animation.HasTimeline(ids)) { || timeline is DrawOrderFolderTimeline || timeline is EventTimeline
|| !to.animation.HasTimeline(ids)) {
timelineMode[i] = AnimationState.First; timelineMode[i] = AnimationState.First;
} else { } else {
for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) { for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) {

View File

@ -1216,34 +1216,26 @@ namespace Spine {
} }
// Draw order timeline. // Draw order timeline.
int slotCount = skeletonData.slots.Count;
int drawOrderCount = input.ReadInt(true); int drawOrderCount = input.ReadInt(true);
if (drawOrderCount > 0) { if (drawOrderCount > 0) {
var timeline = new DrawOrderTimeline(drawOrderCount); var timeline = new DrawOrderTimeline(drawOrderCount);
int slotCount = skeletonData.slots.Count; for (int i = 0; i < drawOrderCount; i++)
for (int i = 0; i < drawOrderCount; i++) { timeline.SetFrame(i, input.ReadFloat(), ReadDrawOrder(input, slotCount));
float time = input.ReadFloat(); timelines.Add(timeline);
int offsetCount = input.ReadInt(true); }
var drawOrder = new int[slotCount];
for (int ii = slotCount - 1; ii >= 0; ii--) // Draw order folder timelines.
drawOrder[ii] = -1; int folderCount = input.ReadInt(true);
var unchanged = new int[slotCount - offsetCount]; for (int i = 0; i < folderCount; i++) {
int originalIndex = 0, unchangedIndex = 0; int folderSlotCount = input.ReadInt(true);
for (int ii = 0; ii < offsetCount; ii++) { var folderSlots = new int[folderSlotCount];
int slotIndex = input.ReadInt(true); for (int ii = 0; ii < folderSlotCount; ii++)
// Collect unchanged items. folderSlots[ii] = input.ReadInt(true);
while (originalIndex != slotIndex) int keyCount = input.ReadInt(true);
unchanged[unchangedIndex++] = originalIndex++; var timeline = new DrawOrderFolderTimeline(keyCount, folderSlots, slotCount);
// Set changed items. for (int ii = 0; ii < keyCount; ii++)
drawOrder[originalIndex + input.ReadInt(true)] = originalIndex++; timeline.SetFrame(ii, input.ReadFloat(), ReadDrawOrder(input, folderSlotCount));
}
// Collect remaining unchanged items.
while (originalIndex < slotCount)
unchanged[unchangedIndex++] = originalIndex++;
// Fill in unchanged items.
for (int ii = slotCount - 1; ii >= 0; ii--)
if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex];
timeline.SetFrame(i, time, drawOrder);
}
timelines.Add(timeline); timelines.Add(timeline);
} }
@ -1319,6 +1311,32 @@ namespace Spine {
timelines.Add(timeline); timelines.Add(timeline);
} }
/// <exception cref="IOException">Throws IOException when a read operation fails.</exception>
private int[] ReadDrawOrder (SkeletonInput input, int slotCount) {
int changeCount = input.ReadInt(true);
if (changeCount == 0) return null;
var drawOrder = new int[slotCount];
for (int ii = slotCount - 1; ii >= 0; ii--)
drawOrder[ii] = -1;
var unchanged = new int[slotCount - changeCount];
int originalIndex = 0, unchangedIndex = 0;
for (int i = 0; i < changeCount; i++) {
int slotIndex = input.ReadInt(true);
// Collect unchanged items.
while (originalIndex != slotIndex)
unchanged[unchangedIndex++] = originalIndex++;
// Set changed items.
drawOrder[originalIndex + input.ReadInt(true)] = originalIndex++;
}
// Collect remaining unchanged items.
while (originalIndex < slotCount)
unchanged[unchangedIndex++] = originalIndex++;
// Fill in unchanged items.
for (int i = slotCount - 1; i >= 0; i--)
if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex];
return drawOrder;
}
/// <exception cref="IOException">Throws IOException when a read operation fails.</exception> /// <exception cref="IOException">Throws IOException when a read operation fails.</exception>
void SetBezier (SkeletonInput input, CurveTimeline timeline, int bezier, int frame, int value, float time1, float time2, void SetBezier (SkeletonInput input, CurveTimeline timeline, int bezier, int frame, int value, float time1, float time2,
float value1, float value2, float scale) { float value1, float value2, float scale) {

View File

@ -469,7 +469,9 @@ namespace Spine {
skin.constraints.TrimExcess(); skin.constraints.TrimExcess();
if (skinMap.ContainsKey("attachments")) { if (skinMap.ContainsKey("attachments")) {
foreach (KeyValuePair<string, Object> slotEntry in (Dictionary<string, Object>)skinMap["attachments"]) { foreach (KeyValuePair<string, Object> slotEntry in (Dictionary<string, Object>)skinMap["attachments"]) {
int slotIndex = FindSlotIndex(skeletonData, slotEntry.Key); SlotData slot = skeletonData.FindSlot(slotEntry.Key);
if (slot == null) throw new Exception("Skin slot not found: " + slotEntry.Key);
int slotIndex = slot.Index;
foreach (KeyValuePair<string, Object> entry in ((Dictionary<string, Object>)slotEntry.Value)) { foreach (KeyValuePair<string, Object> entry in ((Dictionary<string, Object>)slotEntry.Value)) {
try { try {
Attachment attachment = ReadAttachment((Dictionary<string, Object>)entry.Value, skin, slotIndex, entry.Key, skeletonData); Attachment attachment = ReadAttachment((Dictionary<string, Object>)entry.Value, skin, slotIndex, entry.Key, skeletonData);
@ -728,13 +730,6 @@ namespace Spine {
attachment.vertices = weights.ToArray(); attachment.vertices = weights.ToArray();
} }
private int FindSlotIndex (SkeletonData skeletonData, string slotName) {
SlotData[] slots = skeletonData.slots.Items;
for (int i = 0, n = skeletonData.slots.Count; i < n; i++)
if (slots[i].name == slotName) return i;
throw new Exception("Slot not found: " + slotName);
}
private void ReadAnimation (Dictionary<string, Object> map, string name, SkeletonData skeletonData) { private void ReadAnimation (Dictionary<string, Object> map, string name, SkeletonData skeletonData) {
float scale = this.scale; float scale = this.scale;
var timelines = new ExposedList<Timeline>(); var timelines = new ExposedList<Timeline>();
@ -743,7 +738,9 @@ namespace Spine {
if (map.ContainsKey("slots")) { if (map.ContainsKey("slots")) {
foreach (KeyValuePair<string, Object> entry in (Dictionary<string, Object>)map["slots"]) { foreach (KeyValuePair<string, Object> entry in (Dictionary<string, Object>)map["slots"]) {
string slotName = entry.Key; string slotName = entry.Key;
int slotIndex = FindSlotIndex(skeletonData, slotName); SlotData slot = skeletonData.FindSlot(slotName);
if (slot == null) throw new SerializationException("Slot not found: " + slotName);
int slotIndex = slot.Index;
Dictionary<string, object> timelineMap = (Dictionary<string, Object>)entry.Value; Dictionary<string, object> timelineMap = (Dictionary<string, Object>)entry.Value;
foreach (KeyValuePair<string, Object> timelineEntry in timelineMap) { foreach (KeyValuePair<string, Object> timelineEntry in timelineMap) {
List<object> values = (List<Object>)timelineEntry.Value; List<object> values = (List<Object>)timelineEntry.Value;
@ -752,7 +749,7 @@ namespace Spine {
string timelineName = (string)timelineEntry.Key; string timelineName = (string)timelineEntry.Key;
switch (timelineName) { switch (timelineName) {
case "attachment": { case "attachment": {
var timeline = new AttachmentTimeline(frames, slotIndex); var timeline = new AttachmentTimeline(frames, slot.Index);
int frame = 0; int frame = 0;
foreach (Dictionary<string, Object> keyMap in values) { foreach (Dictionary<string, Object> keyMap in values) {
timeline.SetFrame(frame++, GetFloat(keyMap, "time", 0), GetString(keyMap, "name", null)); timeline.SetFrame(frame++, GetFloat(keyMap, "time", 0), GetString(keyMap, "name", null));
@ -1276,7 +1273,7 @@ namespace Spine {
Skin skin = skeletonData.FindSkin(attachmentsMap.Key); Skin skin = skeletonData.FindSkin(attachmentsMap.Key);
foreach (KeyValuePair<string, Object> slotMap in (Dictionary<string, Object>)attachmentsMap.Value) { foreach (KeyValuePair<string, Object> slotMap in (Dictionary<string, Object>)attachmentsMap.Value) {
SlotData slot = skeletonData.FindSlot(slotMap.Key); SlotData slot = skeletonData.FindSlot(slotMap.Key);
if (slot == null) throw new Exception("Slot not found: " + slotMap.Key); if (slot == null) throw new Exception("Attachment slot not found: " + slotMap.Key);
foreach (KeyValuePair<string, Object> attachmentMap in (Dictionary<string, Object>)slotMap.Value) { foreach (KeyValuePair<string, Object> attachmentMap in (Dictionary<string, Object>)slotMap.Value) {
Attachment attachment = skin.GetAttachment(slot.index, attachmentMap.Key); Attachment attachment = skin.GetAttachment(slot.index, attachmentMap.Key);
if (attachment == null) throw new Exception("Timeline attachment not found: " + attachmentMap.Key); if (attachment == null) throw new Exception("Timeline attachment not found: " + attachmentMap.Key);
@ -1358,41 +1355,42 @@ namespace Spine {
// Draw order timeline. // Draw order timeline.
if (map.ContainsKey("drawOrder")) { if (map.ContainsKey("drawOrder")) {
List<object> values = (List<Object>)map["drawOrder"]; List<object> drawOrderMap = (List<object>)map["drawOrder"];
var timeline = new DrawOrderTimeline(values.Count); var timeline = new DrawOrderTimeline(drawOrderMap.Count);
int slotCount = skeletonData.slots.Count; int slotCount = skeletonData.slots.Count, frame = 0;
int frame = 0; foreach (Dictionary<string, object> keyMap in drawOrderMap) {
foreach (Dictionary<string, Object> keyMap in values) { timeline.SetFrame(frame, GetFloat(keyMap, "time", 0), ReadDrawOrder(skeletonData, keyMap, slotCount, null));
int[] drawOrder = null; frame++;
if (keyMap.ContainsKey("offsets")) {
drawOrder = new int[slotCount];
for (int i = slotCount - 1; i >= 0; i--)
drawOrder[i] = -1;
List<object> offsets = (List<Object>)keyMap["offsets"];
int[] unchanged = new int[slotCount - offsets.Count];
int originalIndex = 0, unchangedIndex = 0;
foreach (Dictionary<string, Object> offsetMap in offsets) {
int slotIndex = FindSlotIndex(skeletonData, (string)offsetMap["slot"]);
// Collect unchanged items.
while (originalIndex != slotIndex)
unchanged[unchangedIndex++] = originalIndex++;
// Set changed items.
int index = originalIndex + (int)(float)offsetMap["offset"];
drawOrder[index] = originalIndex++;
}
// Collect remaining unchanged items.
while (originalIndex < slotCount)
unchanged[unchangedIndex++] = originalIndex++;
// Fill in unchanged items.
for (int i = slotCount - 1; i >= 0; i--)
if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex];
}
timeline.SetFrame(frame, GetFloat(keyMap, "time", 0), drawOrder);
++frame;
} }
timelines.Add(timeline); timelines.Add(timeline);
} }
// Draw order folder timelines.
if (map.ContainsKey("drawOrderFolder")) {
List<object> drawOrderFolderMap = (List<object>)map["drawOrderFolder"];
foreach (Dictionary<string, object> timelineMap in drawOrderFolderMap) {
List<object> slotEntries = (List<object>)timelineMap["slots"];
var folderSlots = new int[slotEntries.Count];
int ii = 0;
foreach (string slotEntry in slotEntries) {
SlotData slot = skeletonData.FindSlot(slotEntry);
if (slot == null) throw new SerializationException("Draw order folder slot not found: " + slotEntry);
folderSlots[ii] = slot.index;
ii++;
}
List<object> keys = (List<object>)timelineMap["keys"];
var timeline = new DrawOrderFolderTimeline(keys.Count, folderSlots, skeletonData.slots.Count);
int frame = 0;
foreach (Dictionary<string, object> keyMap in keys) {
timeline.SetFrame(frame, GetFloat(keyMap, "time", 0),
ReadDrawOrder(skeletonData, keyMap, folderSlots.Length, folderSlots));
frame++;
}
timelines.Add(timeline);
}
}
// Event timeline. // Event timeline.
if (map.ContainsKey("events")) { if (map.ContainsKey("events")) {
List<object> eventsMap = (List<Object>)map["events"]; List<object> eventsMap = (List<Object>)map["events"];
@ -1477,6 +1475,48 @@ namespace Spine {
} }
} }
/// <param name="folderSlots">
/// Slot names are resolved to positions within this array. If null, slot indices are used as positions.</param>
private int[] ReadDrawOrder (SkeletonData skeletonData, Dictionary<string, object> keyMap, int slotCount, int[] folderSlots) {
if (!keyMap.ContainsKey("offsets")) return null; // Setup draw order.
List<object> changes = (List<object>)keyMap["offsets"];
var drawOrder = new int[slotCount];
for (int ii = slotCount - 1; ii >= 0; ii--)
drawOrder[ii] = -1;
var unchanged = new int[slotCount - changes.Count];
int originalIndex = 0, unchangedIndex = 0;
foreach (Dictionary<string, object> offsetMap in changes) {
SlotData slot = skeletonData.FindSlot((string)offsetMap["slot"]);
if (slot == null) throw new SerializationException("Draw order slot not found: " + (string)offsetMap["slot"]);
int index;
if (folderSlots == null)
index = slot.index;
else {
index = -1;
for (int i = 0; i < slotCount; i++) {
if (folderSlots[i] == slot.index) {
index = i;
break;
}
}
if (index == -1) throw new SerializationException("Slot not in folder: " + (string)offsetMap["slot"]);
}
// Collect unchanged items.
while (originalIndex != index)
unchanged[unchangedIndex++] = originalIndex++;
// Set changed items.
drawOrder[originalIndex + GetInt(offsetMap, "offset")] = originalIndex++;
}
// Collect remaining unchanged items.
while (originalIndex < slotCount)
unchanged[unchangedIndex++] = originalIndex++;
// Fill in unchanged items.
for (int i = slotCount - 1; i >= 0; i--)
if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex];
return drawOrder;
}
static int ReadCurve (object curve, CurveTimeline timeline, int bezier, int frame, int value, float time1, float time2, static int ReadCurve (object curve, CurveTimeline timeline, int bezier, int frame, int value, float time1, float time2,
float value1, float value2, float scale) { float value1, float value2, float scale) {

View File

@ -2,7 +2,7 @@
"name": "com.esotericsoftware.spine.spine-csharp", "name": "com.esotericsoftware.spine.spine-csharp",
"displayName": "spine-csharp Runtime", "displayName": "spine-csharp Runtime",
"description": "This plugin provides the spine-csharp core runtime. Compatible with skeleton exports from Spine Editor version 4.3.40-beta or later.", "description": "This plugin provides the spine-csharp core runtime. Compatible with skeleton exports from Spine Editor version 4.3.40-beta or later.",
"version": "4.3.15", "version": "4.3.16",
"unity": "2018.3", "unity": "2018.3",
"author": { "author": {
"name": "Esoteric Software", "name": "Esoteric Software",

View File

@ -1,7 +1,7 @@
{ {
"skeleton": { "skeleton": {
"hash": "UKNfIjHXMsA", "hash": "H2dY262/ZMA",
"spine": "4.3.40-beta", "spine": "4.3.45-beta",
"x": -434, "x": -434,
"y": -133, "y": -133,
"width": 868, "width": 868,

View File

@ -1,7 +1,7 @@
{ {
"skeleton": { "skeleton": {
"hash": "w8qTGu8i+Jo", "hash": "RqbWpWhrJhQ",
"spine": "4.3.40-beta", "spine": "4.3.45-beta",
"x": -125, "x": -125,
"y": -30, "y": -30,
"width": 250, "width": 250,
@ -41,7 +41,7 @@
"scale": [ "scale": [
{ {
"x": 0.002, "x": 0.002,
"curve": [ 0.25, 0.002, 0.75000006, 1, 0.25, 1, 0.75000006, 1 ] "curve": [ 0.25, 0.002, 0.75, 1, 0.25, 1, 0.75, 1 ]
}, },
{ "time": 1 } { "time": 1 }
] ]

View File

@ -1,10 +1,10 @@
{ {
"skeleton": { "skeleton": {
"hash": "Vjuwy5lHe4I", "hash": "kCU6F/siLYE",
"spine": "4.3.40-beta", "spine": "4.3.45-beta",
"x": -78.44883, "x": -78.44883,
"y": -9.661293, "y": -9.661293,
"width": 157.48239, "width": 157.4824,
"height": 364.9783, "height": 364.9783,
"images": "./images/", "images": "./images/",
"audio": null "audio": null
@ -120,7 +120,7 @@
"abdomen": { "abdomen": {
"rotate": [ "rotate": [
{ {
"curve": [ 0.075, 0, 0.112200014, 6.52 ] "curve": [ 0.075, 0, 0.1122, 6.52 ]
}, },
{ "time": 0.3, "value": 6.52 }, { "time": 0.3, "value": 6.52 },
{ "time": 1.3333334 } { "time": 1.3333334 }
@ -132,55 +132,75 @@
"curve": [ 0.09166667, 0, 0.13713335, 13.73 ] "curve": [ 0.09166667, 0, 0.13713335, 13.73 ]
}, },
{ {
"time": 0.36666667, "time": 0.3666667,
"value": 13.73, "value": 13.73,
"curve": [ 0.46866667, 13.73, 0.5619667, 13.3215 ] "curve": [ 0.4686666, 13.73, 0.5619667, 13.3215 ]
}, },
{ {
"time": 0.6666667, "time": 0.6666667,
"value": 12.78, "value": 12.78,
"curve": [ 0.7702667, 12.78, 0.8416667, 9.11 ] "curve": [ 0.7702666, 12.78, 0.8416666, 9.11 ]
}, },
{ {
"time": 0.90000004, "time": 0.9,
"value": 9.11, "value": 9.11,
"curve": [ 1.0924001, 9.11, 1.225, 0 ] "curve": [ 1.0924, 9.11, 1.225, 0 ]
}, },
{ "time": 1.3333334 } { "time": 1.3333334 }
] ]
}, },
"hair1": {
"rotate": [
{
"value": -8.8,
"curve": [ 0.06666667, -8.8, 0.09973334, -16.02 ]
},
{
"time": 0.2666667,
"value": -16.02,
"curve": [ 0.3333333, -16.02, 0.4096, 29.39 ]
},
{
"time": 0.5333333,
"value": 29.39,
"curve": [ 0.7333333, 29.39, 0.8845333, -8.8 ]
},
{ "time": 1.3333334, "value": -8.8 }
]
},
"hair2": {
"rotate": [
{
"value": 4.65,
"curve": [ 0.14133333, 4.65, 0.12466667, -17.96 ]
},
{
"time": 0.3333333,
"value": -17.96,
"curve": [ 0.4083333, -17.96, 0.49413335, 6.630001 ]
},
{
"time": 0.6333333,
"value": 6.630001,
"curve": [ 0.8083333, 6.630001, 0.9406333, 4.65 ]
},
{ "time": 1.3333334, "value": 4.65 }
]
},
"head": { "head": {
"rotate": [ "rotate": [
{ {
"curve": [ 0.0348, 0, 0.060900006, -5.44 ] "curve": [ 0.0348, 0, 0.06090001, -5.44 ]
}, },
{ {
"time": 0.10000001, "time": 0.1,
"value": -10.88, "value": -10.88,
"curve": [ 0.18333334, -10.88, 0.35000002, 6.7699995 ] "curve": [ 0.18333334, -10.88, 0.35, 6.77 ]
}, },
{ {
"time": 0.43333337, "time": 0.4333333,
"value": 6.7699995, "value": 6.77,
"curve": [ 1.1569334, 6.7699995, 0.9661334, 0.13539982 ] "curve": [ 1.1569333, 6.77, 0.9661333, 0.1353998 ]
},
{ "time": 1.3333334 }
]
},
"R-arm": {
"rotate": [
{
"curve": [ 0.041666668, 0, 0.125, -26.35 ]
},
{
"time": 0.16666667,
"value": -26.35,
"curve": [ 0.23333335, -26.35, 0.36666667, -6.09 ]
},
{
"time": 0.43333337,
"value": -6.09,
"curve": [ 0.65833336, -6.09, 1.1083333, 0 ]
}, },
{ "time": 1.3333334 } { "time": 1.3333334 }
] ]
@ -188,115 +208,95 @@
"L-arm": { "L-arm": {
"rotate": [ "rotate": [
{ {
"curve": [ 0.083333336, 0, 0.12466668, 53.01 ] "curve": [ 0.08333333, 0, 0.12466667, 53.01 ]
}, },
{ {
"time": 0.33333334, "time": 0.3333333,
"value": 53.01, "value": 53.01,
"curve": [ 0.47653335, 52.831097, 0.53840005, 35.12 ] "curve": [ 0.4765333, 52.8311, 0.5384, 35.12 ]
}, },
{ {
"time": 0.6, "time": 0.6,
"value": 35.12, "value": 35.12,
"curve": [ 0.68166673, 35.12, 0.75376666, 56.78 ] "curve": [ 0.6816667, 35.12, 0.7537666, 56.78 ]
}, },
{ {
"time": 0.8333334, "time": 0.8333333,
"value": 56.78, "value": 56.78,
"curve": [ 1.1283333, 56.78, 1.1808333, 0 ] "curve": [ 1.1283333, 56.78, 1.1808333, 0 ]
}, },
{ "time": 1.3333334 } { "time": 1.3333334 }
] ]
}, },
"R-forearm": {
"rotate": [
{
"curve": [ 0.116000004, 0, 0.20300001, 4.89 ]
},
{
"time": 0.33333334,
"value": 9.78,
"curve": [ 0.5833334, 9.78, 0.8043333, 0 ]
},
{ "time": 1.3333334 }
]
},
"L-forearm": { "L-forearm": {
"rotate": [ "rotate": [
{ {
"value": 14.9, "value": 14.9,
"curve": [ 0.14343335, -80.79261, 0.22880001, 32.08 ] "curve": [ 0.14343333, -80.7926, 0.2288, 32.08 ]
}, },
{ {
"time": 0.43333337, "time": 0.4333333,
"value": 32.08, "value": 32.08,
"curve": [ 0.5617334, 32.08, 0.49693337, -11.739998 ] "curve": [ 0.5617333, 32.08, 0.4969333, -11.739998 ]
}, },
{ {
"time": 0.6333334, "time": 0.6333333,
"value": -11.739998, "value": -11.739998,
"curve": [ 0.8139334, -11.739998, 0.74913335, 58 ] "curve": [ 0.8139333, -11.739998, 0.7491333, 58 ]
}, },
{ {
"time": 0.9333334, "time": 0.9333333,
"value": 58, "value": 58,
"curve": [ 1.0333334, 58, 1.1849334, 14.900002 ] "curve": [ 1.0333333, 58, 1.1849333, 14.900002 ]
}, },
{ "time": 1.3333334, "value": 14.900002 } { "time": 1.3333334, "value": 14.900002 }
] ]
}, },
"R-arm": {
"rotate": [
{
"curve": [ 0.04166667, 0, 0.125, -26.35 ]
},
{
"time": 0.16666667,
"value": -26.35,
"curve": [ 0.23333333, -26.35, 0.3666667, -6.09 ]
},
{
"time": 0.4333333,
"value": -6.09,
"curve": [ 0.6583333, -6.09, 1.1083333, 0 ]
},
{ "time": 1.3333334 }
]
},
"R-forearm": {
"rotate": [
{
"curve": [ 0.116, 0, 0.203, 4.89 ]
},
{
"time": 0.3333333,
"value": 9.78,
"curve": [ 0.5833333, 9.78, 0.8043333, 0 ]
},
{ "time": 1.3333334 }
]
},
"scalp": { "scalp": {
"rotate": [ "rotate": [
{ {
"value": -7.01, "value": -7.01,
"curve": [ 0.0952, -7.01, 0.17146668, -0.43100023 ] "curve": [ 0.0952, -7.01, 0.17146666, -0.4310002 ]
}, },
{ {
"time": 0.26666668, "time": 0.2666667,
"value": 7.6100006, "value": 7.61,
"curve": [ 0.3498667, 4.2616005, 0.4582667, 0 ] "curve": [ 0.3498667, 4.2616, 0.4582667, 0 ]
}, },
{ "time": 0.6666667 }, { "time": 0.6666667 },
{ "time": 1.3333334, "value": -7.01 } { "time": 1.3333334, "value": -7.01 }
] ]
},
"hair1": {
"rotate": [
{
"value": -8.8,
"curve": [ 0.06666667, -8.8, 0.099733345, -16.02 ]
},
{
"time": 0.26666668,
"value": -16.02,
"curve": [ 0.33333334, -16.02, 0.40960002, 29.39 ]
},
{
"time": 0.53333336,
"value": 29.39,
"curve": [ 0.73333335, 29.39, 0.88453335, -8.799999 ]
},
{ "time": 1.3333334, "value": -8.799999 }
]
},
"hair2": {
"rotate": [
{
"value": 4.65,
"curve": [ 0.14133333, 4.65, 0.12466668, -17.96 ]
},
{
"time": 0.33333334,
"value": -17.96,
"curve": [ 0.40833336, -17.96, 0.49413338, 6.630001 ]
},
{
"time": 0.6333334,
"value": 6.630001,
"curve": [ 0.8083334, 6.630001, 0.94063336, 4.65 ]
},
{ "time": 1.3333334, "value": 4.65 }
]
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,11 @@
{ {
"skeleton": { "skeleton": {
"hash": "acq/cF9RZNM", "hash": "DFau1C+kFtw",
"spine": "4.3.40-beta", "spine": "4.3.45-beta",
"x": -252.71397, "x": -252.71397,
"y": -232.55397, "y": -232.55397,
"width": 456.70795, "width": 456.70795,
"height": 360.68793, "height": 360.6879,
"images": "./images/", "images": "./images/",
"audio": null "audio": null
}, },
@ -63,7 +63,7 @@
"_rotation": { "_rotation": {
"rotate": [ "rotate": [
{}, {},
{ "time": 0.33333334, "value": -120 }, { "time": 0.3333333, "value": -120 },
{ "time": 0.6666667, "value": -240 }, { "time": 0.6666667, "value": -240 },
{ "time": 1, "value": -360 } { "time": 1, "value": -360 }
] ]

View File

@ -2,7 +2,7 @@
"name": "com.esotericsoftware.spine.spine-unity", "name": "com.esotericsoftware.spine.spine-unity",
"displayName": "spine-unity Runtime", "displayName": "spine-unity Runtime",
"description": "This plugin provides the spine-unity runtime core and examples. Spine Examples can be installed via the Samples tab.", "description": "This plugin provides the spine-unity runtime core and examples. Spine Examples can be installed via the Samples tab.",
"version": "4.3.56", "version": "4.3.57",
"unity": "2018.3", "unity": "2018.3",
"author": { "author": {
"name": "Esoteric Software", "name": "Esoteric Software",