[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>
public class DrawOrderTimeline : Timeline {
static readonly string[] propertyIds = { ((int)Property.DrawOrder).ToString() };
internal static readonly string[] propertyIds = { ((int)Property.DrawOrder).ToString() };
readonly int[][] drawOrders;
@ -2034,16 +2034,13 @@ namespace Spine {
/// <summary>The draw order for each frame. </summary>
/// <seealso cref="Timeline.SetFrame(int, float, int[])"/>.
public int[][] DrawOrders {
get {
return 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">For each slot in <see cref="Skeleton.Slots"/>, the index of the slot in the new draw order. May be null to use
/// setup pose draw order.</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;
@ -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 {
/// <summary>
/// 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))
timelineMode[i] = AnimationState.Subsequent;
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;
} else {
for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) {

View File

@ -1216,34 +1216,26 @@ namespace Spine {
}
// Draw order timeline.
int slotCount = skeletonData.slots.Count;
int drawOrderCount = input.ReadInt(true);
if (drawOrderCount > 0) {
var timeline = new DrawOrderTimeline(drawOrderCount);
int slotCount = skeletonData.slots.Count;
for (int i = 0; i < drawOrderCount; i++) {
float time = input.ReadFloat();
int offsetCount = input.ReadInt(true);
var drawOrder = new int[slotCount];
for (int ii = slotCount - 1; ii >= 0; ii--)
drawOrder[ii] = -1;
var unchanged = new int[slotCount - offsetCount];
int originalIndex = 0, unchangedIndex = 0;
for (int ii = 0; ii < offsetCount; ii++) {
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 ii = slotCount - 1; ii >= 0; ii--)
if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex];
timeline.SetFrame(i, time, drawOrder);
}
for (int i = 0; i < drawOrderCount; i++)
timeline.SetFrame(i, input.ReadFloat(), ReadDrawOrder(input, slotCount));
timelines.Add(timeline);
}
// Draw order folder timelines.
int folderCount = input.ReadInt(true);
for (int i = 0; i < folderCount; i++) {
int folderSlotCount = input.ReadInt(true);
var folderSlots = new int[folderSlotCount];
for (int ii = 0; ii < folderSlotCount; ii++)
folderSlots[ii] = input.ReadInt(true);
int keyCount = input.ReadInt(true);
var timeline = new DrawOrderFolderTimeline(keyCount, folderSlots, slotCount);
for (int ii = 0; ii < keyCount; ii++)
timeline.SetFrame(ii, input.ReadFloat(), ReadDrawOrder(input, folderSlotCount));
timelines.Add(timeline);
}
@ -1319,6 +1311,32 @@ namespace Spine {
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>
void SetBezier (SkeletonInput input, CurveTimeline timeline, int bezier, int frame, int value, float time1, float time2,
float value1, float value2, float scale) {

View File

@ -469,7 +469,9 @@ namespace Spine {
skin.constraints.TrimExcess();
if (skinMap.ContainsKey("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)) {
try {
Attachment attachment = ReadAttachment((Dictionary<string, Object>)entry.Value, skin, slotIndex, entry.Key, skeletonData);
@ -728,13 +730,6 @@ namespace Spine {
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) {
float scale = this.scale;
var timelines = new ExposedList<Timeline>();
@ -743,7 +738,9 @@ namespace Spine {
if (map.ContainsKey("slots")) {
foreach (KeyValuePair<string, Object> entry in (Dictionary<string, Object>)map["slots"]) {
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;
foreach (KeyValuePair<string, Object> timelineEntry in timelineMap) {
List<object> values = (List<Object>)timelineEntry.Value;
@ -752,7 +749,7 @@ namespace Spine {
string timelineName = (string)timelineEntry.Key;
switch (timelineName) {
case "attachment": {
var timeline = new AttachmentTimeline(frames, slotIndex);
var timeline = new AttachmentTimeline(frames, slot.Index);
int frame = 0;
foreach (Dictionary<string, Object> keyMap in values) {
timeline.SetFrame(frame++, GetFloat(keyMap, "time", 0), GetString(keyMap, "name", null));
@ -1276,7 +1273,7 @@ namespace Spine {
Skin skin = skeletonData.FindSkin(attachmentsMap.Key);
foreach (KeyValuePair<string, Object> slotMap in (Dictionary<string, Object>)attachmentsMap.Value) {
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) {
Attachment attachment = skin.GetAttachment(slot.index, attachmentMap.Key);
if (attachment == null) throw new Exception("Timeline attachment not found: " + attachmentMap.Key);
@ -1358,41 +1355,42 @@ namespace Spine {
// Draw order timeline.
if (map.ContainsKey("drawOrder")) {
List<object> values = (List<Object>)map["drawOrder"];
var timeline = new DrawOrderTimeline(values.Count);
int slotCount = skeletonData.slots.Count;
int frame = 0;
foreach (Dictionary<string, Object> keyMap in values) {
int[] drawOrder = null;
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;
List<object> drawOrderMap = (List<object>)map["drawOrder"];
var timeline = new DrawOrderTimeline(drawOrderMap.Count);
int slotCount = skeletonData.slots.Count, frame = 0;
foreach (Dictionary<string, object> keyMap in drawOrderMap) {
timeline.SetFrame(frame, GetFloat(keyMap, "time", 0), ReadDrawOrder(skeletonData, keyMap, slotCount, null));
frame++;
}
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.
if (map.ContainsKey("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,
float value1, float value2, float scale) {

View File

@ -2,7 +2,7 @@
"name": "com.esotericsoftware.spine.spine-csharp",
"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.",
"version": "4.3.15",
"version": "4.3.16",
"unity": "2018.3",
"author": {
"name": "Esoteric Software",

View File

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

View File

@ -1,7 +1,7 @@
{
"skeleton": {
"hash": "w8qTGu8i+Jo",
"spine": "4.3.40-beta",
"hash": "RqbWpWhrJhQ",
"spine": "4.3.45-beta",
"x": -125,
"y": -30,
"width": 250,
@ -41,7 +41,7 @@
"scale": [
{
"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 }
]

View File

@ -1,10 +1,10 @@
{
"skeleton": {
"hash": "Vjuwy5lHe4I",
"spine": "4.3.40-beta",
"hash": "kCU6F/siLYE",
"spine": "4.3.45-beta",
"x": -78.44883,
"y": -9.661293,
"width": 157.48239,
"width": 157.4824,
"height": 364.9783,
"images": "./images/",
"audio": null
@ -120,7 +120,7 @@
"abdomen": {
"rotate": [
{
"curve": [ 0.075, 0, 0.112200014, 6.52 ]
"curve": [ 0.075, 0, 0.1122, 6.52 ]
},
{ "time": 0.3, "value": 6.52 },
{ "time": 1.3333334 }
@ -132,55 +132,75 @@
"curve": [ 0.09166667, 0, 0.13713335, 13.73 ]
},
{
"time": 0.36666667,
"time": 0.3666667,
"value": 13.73,
"curve": [ 0.46866667, 13.73, 0.5619667, 13.3215 ]
"curve": [ 0.4686666, 13.73, 0.5619667, 13.3215 ]
},
{
"time": 0.6666667,
"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,
"curve": [ 1.0924001, 9.11, 1.225, 0 ]
"curve": [ 1.0924, 9.11, 1.225, 0 ]
},
{ "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": {
"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,
"curve": [ 0.18333334, -10.88, 0.35000002, 6.7699995 ]
"curve": [ 0.18333334, -10.88, 0.35, 6.77 ]
},
{
"time": 0.43333337,
"value": 6.7699995,
"curve": [ 1.1569334, 6.7699995, 0.9661334, 0.13539982 ]
},
{ "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": 0.4333333,
"value": 6.77,
"curve": [ 1.1569333, 6.77, 0.9661333, 0.1353998 ]
},
{ "time": 1.3333334 }
]
@ -188,115 +208,95 @@
"L-arm": {
"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,
"curve": [ 0.47653335, 52.831097, 0.53840005, 35.12 ]
"curve": [ 0.4765333, 52.8311, 0.5384, 35.12 ]
},
{
"time": 0.6,
"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,
"curve": [ 1.1283333, 56.78, 1.1808333, 0 ]
},
{ "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": {
"rotate": [
{
"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,
"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,
"curve": [ 0.8139334, -11.739998, 0.74913335, 58 ]
"curve": [ 0.8139333, -11.739998, 0.7491333, 58 ]
},
{
"time": 0.9333334,
"time": 0.9333333,
"value": 58,
"curve": [ 1.0333334, 58, 1.1849334, 14.900002 ]
"curve": [ 1.0333333, 58, 1.1849333, 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": {
"rotate": [
{
"value": -7.01,
"curve": [ 0.0952, -7.01, 0.17146668, -0.43100023 ]
"curve": [ 0.0952, -7.01, 0.17146666, -0.4310002 ]
},
{
"time": 0.26666668,
"value": 7.6100006,
"curve": [ 0.3498667, 4.2616005, 0.4582667, 0 ]
"time": 0.2666667,
"value": 7.61,
"curve": [ 0.3498667, 4.2616, 0.4582667, 0 ]
},
{ "time": 0.6666667 },
{ "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": {
"hash": "acq/cF9RZNM",
"spine": "4.3.40-beta",
"hash": "DFau1C+kFtw",
"spine": "4.3.45-beta",
"x": -252.71397,
"y": -232.55397,
"width": 456.70795,
"height": 360.68793,
"height": 360.6879,
"images": "./images/",
"audio": null
},
@ -63,7 +63,7 @@
"_rotation": {
"rotate": [
{},
{ "time": 0.33333334, "value": -120 },
{ "time": 0.3333333, "value": -120 },
{ "time": 0.6666667, "value": -240 },
{ "time": 1, "value": -360 }
]

View File

@ -2,7 +2,7 @@
"name": "com.esotericsoftware.spine.spine-unity",
"displayName": "spine-unity Runtime",
"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",
"author": {
"name": "Esoteric Software",