mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-01 13:19:08 +08:00
Merge branch 'master' into 3.6-beta
This commit is contained in:
commit
6fb9a4e991
Binary file not shown.
@ -366,7 +366,7 @@ public class AnimationState {
|
|||||||
from.timelinesRotation.length = 0;
|
from.timelinesRotation.length = 0;
|
||||||
|
|
||||||
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
||||||
if (from.mixingFrom != null) current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
if (from.mixingFrom != null && from.mixDuration > 0) current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.start(current);
|
queue.start(current);
|
||||||
@ -485,7 +485,7 @@ public class AnimationState {
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? int.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = int.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
|
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
|
|||||||
@ -126,7 +126,7 @@ public class Atlas {
|
|||||||
region.splits = new Vector.<int>(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3]));
|
region.splits = new Vector.<int>(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3]));
|
||||||
|
|
||||||
if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits
|
if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits
|
||||||
region.pads = Vector.<int>(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3]));
|
region.pads = new Vector.<int>(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3]));
|
||||||
|
|
||||||
reader.readTuple(tuple);
|
reader.readTuple(tuple);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -582,7 +582,7 @@ void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEnt
|
|||||||
from->timelinesRotationCount = 0;
|
from->timelinesRotationCount = 0;
|
||||||
|
|
||||||
/* If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero. */
|
/* If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero. */
|
||||||
if (from->mixingFrom) current->mixAlpha *= MIN(from->mixTime / from->mixDuration, 1);
|
if (from->mixingFrom && from->mixDuration > 0) current->mixAlpha *= MIN(from->mixTime / from->mixDuration, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_spEventQueue_start(internal->queue, current);
|
_spEventQueue_start(internal->queue, current);
|
||||||
@ -715,7 +715,7 @@ spTrackEntry* _spAnimationState_trackEntry (spAnimationState* self, int trackInd
|
|||||||
entry->trackTime = 0;
|
entry->trackTime = 0;
|
||||||
entry->trackLast = -1;
|
entry->trackLast = -1;
|
||||||
entry->nextTrackLast = -1;
|
entry->nextTrackLast = -1;
|
||||||
entry->trackEnd = loop ? (float)INT_MAX : entry->animationEnd;
|
entry->trackEnd = (float)INT_MAX;
|
||||||
entry->timeScale = 1;
|
entry->timeScale = 1;
|
||||||
|
|
||||||
entry->alpha = 1;
|
entry->alpha = 1;
|
||||||
|
|||||||
@ -66,11 +66,11 @@ typedef struct {
|
|||||||
} Str;
|
} Str;
|
||||||
|
|
||||||
static void trim (Str* str) {
|
static void trim (Str* str) {
|
||||||
while (isspace(*str->begin) && str->begin < str->end)
|
while (isspace((unsigned char)*str->begin) && str->begin < str->end)
|
||||||
(str->begin)++;
|
(str->begin)++;
|
||||||
if (str->begin == str->end) return;
|
if (str->begin == str->end) return;
|
||||||
str->end--;
|
str->end--;
|
||||||
while (isspace(*str->end) && str->end >= str->begin)
|
while (isspace((unsigned char)*str->end) && str->end >= str->begin)
|
||||||
str->end--;
|
str->end--;
|
||||||
str->end++;
|
str->end++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
#include "kvec.h"
|
#include "kvec.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const unsigned char* cursor;
|
const unsigned char* cursor;
|
||||||
const unsigned char* end;
|
const unsigned char* end;
|
||||||
} _dataInput;
|
} _dataInput;
|
||||||
|
|
||||||
@ -373,7 +373,7 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
|
|||||||
for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
|
for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
|
||||||
float time = readFloat(input);
|
float time = readFloat(input);
|
||||||
float mix = readFloat(input);
|
float mix = readFloat(input);
|
||||||
char bendDirection = readSByte(input);
|
signed char bendDirection = readSByte(input);
|
||||||
spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, bendDirection);
|
spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, bendDirection);
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex);
|
if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,11 +30,10 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Spine {
|
namespace Spine {
|
||||||
public class AnimationState {
|
public class AnimationState {
|
||||||
private static Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0);
|
static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0);
|
||||||
|
|
||||||
private AnimationStateData data;
|
private AnimationStateData data;
|
||||||
private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
|
private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
|
||||||
@ -44,6 +43,8 @@ namespace Spine {
|
|||||||
private bool animationsChanged;
|
private bool animationsChanged;
|
||||||
private float timeScale = 1;
|
private float timeScale = 1;
|
||||||
|
|
||||||
|
Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>();
|
||||||
|
|
||||||
public AnimationStateData Data { get { return data; } }
|
public AnimationStateData Data { get { return data; } }
|
||||||
/// <summary>A list of tracks that have animations, which may contain nulls.</summary>
|
/// <summary>A list of tracks that have animations, which may contain nulls.</summary>
|
||||||
public ExposedList<TrackEntry> Tracks { get { return tracks; } }
|
public ExposedList<TrackEntry> Tracks { get { return tracks; } }
|
||||||
@ -58,7 +59,7 @@ namespace Spine {
|
|||||||
public AnimationState (AnimationStateData data) {
|
public AnimationState (AnimationStateData data) {
|
||||||
if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
|
if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.queue = new EventQueue(this, HandleAnimationsChanged);
|
this.queue = new EventQueue(this, HandleAnimationsChanged, trackEntryPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleAnimationsChanged () {
|
void HandleAnimationsChanged () {
|
||||||
@ -215,7 +216,7 @@ namespace Spine {
|
|||||||
float alpha = from.alpha * entry.mixAlpha * (1 - mix);
|
float alpha = from.alpha * entry.mixAlpha * (1 - mix);
|
||||||
|
|
||||||
bool firstFrame = entry.timelinesRotation.Count == 0;
|
bool firstFrame = entry.timelinesRotation.Count == 0;
|
||||||
if (firstFrame) entry.timelinesRotation.Capacity = timelineCount << 1;
|
if (firstFrame) entry.timelinesRotation.EnsureCapacity(timelines.Count << 1);
|
||||||
var timelinesRotation = entry.timelinesRotation.Items;
|
var timelinesRotation = entry.timelinesRotation.Items;
|
||||||
|
|
||||||
for (int i = 0; i < timelineCount; i++) {
|
for (int i = 0; i < timelineCount; i++) {
|
||||||
@ -389,7 +390,7 @@ namespace Spine {
|
|||||||
from.timelinesRotation.Clear();
|
from.timelinesRotation.Clear();
|
||||||
|
|
||||||
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
||||||
if (from.mixingFrom != null) from.mixAlpha *= Math.Min(from.mixTime / from.mixDuration, 1);
|
if (from.mixingFrom != null && from.mixDuration > 0) current.mixAlpha *= Math.Min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.Start(current);
|
queue.Start(current);
|
||||||
@ -526,32 +527,32 @@ namespace Spine {
|
|||||||
|
|
||||||
/// <param name="last">May be null.</param>
|
/// <param name="last">May be null.</param>
|
||||||
private TrackEntry NewTrackEntry (int trackIndex, Animation animation, bool loop, TrackEntry last) {
|
private TrackEntry NewTrackEntry (int trackIndex, Animation animation, bool loop, TrackEntry last) {
|
||||||
return new TrackEntry {
|
TrackEntry entry = trackEntryPool.Obtain(); // Pooling
|
||||||
trackIndex = trackIndex,
|
entry.trackIndex = trackIndex;
|
||||||
animation = animation,
|
entry.animation = animation;
|
||||||
loop = loop,
|
entry.loop = loop;
|
||||||
|
|
||||||
eventThreshold = 0,
|
entry.eventThreshold = 0;
|
||||||
attachmentThreshold = 0,
|
entry.attachmentThreshold = 0;
|
||||||
drawOrderThreshold = 0,
|
entry.drawOrderThreshold = 0;
|
||||||
|
|
||||||
animationStart = 0,
|
entry.animationStart = 0;
|
||||||
animationEnd = animation.duration,
|
entry.animationEnd = animation.Duration;
|
||||||
animationLast = -1,
|
entry.animationLast = -1;
|
||||||
nextAnimationLast = -1,
|
entry.nextAnimationLast = -1;
|
||||||
|
|
||||||
delay = 0,
|
entry.delay = 0;
|
||||||
trackTime = 0,
|
entry.trackTime = 0;
|
||||||
trackLast = -1,
|
entry.trackLast = -1;
|
||||||
nextTrackLast = -1,
|
entry.nextTrackLast = -1;
|
||||||
trackEnd = loop ? int.MaxValue : animation.duration,
|
entry.trackEnd = float.MaxValue; // loop ? float.MaxValue : animation.Duration;
|
||||||
timeScale = 1,
|
entry.timeScale = 1;
|
||||||
|
|
||||||
alpha = 1,
|
entry.alpha = 1;
|
||||||
mixAlpha = 1,
|
entry.mixAlpha = 1;
|
||||||
mixTime = 0,
|
entry.mixTime = 0;
|
||||||
mixDuration = (last == null) ? 0 : data.GetMix(last.animation, animation),
|
entry.mixDuration = (last == null) ? 0 : data.GetMix(last.animation, animation);
|
||||||
};
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeNext (TrackEntry entry) {
|
private void DisposeNext (TrackEntry entry) {
|
||||||
@ -627,7 +628,7 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public String ToString () {
|
override public String ToString () {
|
||||||
var buffer = new StringBuilder();
|
var buffer = new System.Text.StringBuilder();
|
||||||
for (int i = 0, n = tracks.Count; i < n; i++) {
|
for (int i = 0, n = tracks.Count; i < n; i++) {
|
||||||
TrackEntry entry = tracks.Items[i];
|
TrackEntry entry = tracks.Items[i];
|
||||||
if (entry == null) continue;
|
if (entry == null) continue;
|
||||||
@ -646,7 +647,7 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>State for the playback of an animation.</summary>
|
/// <summary>State for the playback of an animation.</summary>
|
||||||
public class TrackEntry {
|
public class TrackEntry : Pool<TrackEntry>.IPoolable {
|
||||||
internal Animation animation;
|
internal Animation animation;
|
||||||
|
|
||||||
internal TrackEntry next, mixingFrom;
|
internal TrackEntry next, mixingFrom;
|
||||||
@ -657,9 +658,25 @@ namespace Spine {
|
|||||||
internal float animationStart, animationEnd, animationLast, nextAnimationLast;
|
internal float animationStart, animationEnd, animationLast, nextAnimationLast;
|
||||||
internal float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale = 1f;
|
internal float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale = 1f;
|
||||||
internal float alpha, mixTime, mixDuration, mixAlpha;
|
internal float alpha, mixTime, mixDuration, mixAlpha;
|
||||||
internal readonly ExposedList<bool> timelinesFirst = new ExposedList<bool>(), timelinesLast = new ExposedList<bool>();
|
internal readonly ExposedList<bool> timelinesFirst = new ExposedList<bool>();
|
||||||
internal readonly ExposedList<float> timelinesRotation = new ExposedList<float>();
|
internal readonly ExposedList<float> timelinesRotation = new ExposedList<float>();
|
||||||
|
|
||||||
|
// IPoolable.Reset()
|
||||||
|
public void Reset () {
|
||||||
|
next = null;
|
||||||
|
mixingFrom = null;
|
||||||
|
animation = null;
|
||||||
|
timelinesFirst.Clear();
|
||||||
|
timelinesRotation.Clear();
|
||||||
|
|
||||||
|
Start = null;
|
||||||
|
Interrupt = null;
|
||||||
|
End = null;
|
||||||
|
Dispose = null;
|
||||||
|
Complete = null;
|
||||||
|
Event = null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>The index of the track where this entry is either current or queued.</summary>
|
/// <summary>The index of the track where this entry is either current or queued.</summary>
|
||||||
public int TrackIndex { get { return trackIndex; } }
|
public int TrackIndex { get { return trackIndex; } }
|
||||||
|
|
||||||
@ -824,11 +841,13 @@ namespace Spine {
|
|||||||
public bool drainDisabled;
|
public bool drainDisabled;
|
||||||
|
|
||||||
private readonly AnimationState state;
|
private readonly AnimationState state;
|
||||||
|
private readonly Pool<TrackEntry> trackEntryPool;
|
||||||
public event Action AnimationsChanged;
|
public event Action AnimationsChanged;
|
||||||
|
|
||||||
public EventQueue (AnimationState state, Action HandleAnimationsChanged) {
|
public EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool<TrackEntry> trackEntryPool) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.AnimationsChanged += HandleAnimationsChanged;
|
this.AnimationsChanged += HandleAnimationsChanged;
|
||||||
|
this.trackEntryPool = trackEntryPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EventQueueEntry {
|
struct EventQueueEntry {
|
||||||
@ -901,6 +920,7 @@ namespace Spine {
|
|||||||
case EventType.Dispose:
|
case EventType.Dispose:
|
||||||
trackEntry.OnDispose();
|
trackEntry.OnDispose();
|
||||||
state.OnDispose(trackEntry);
|
state.OnDispose(trackEntry);
|
||||||
|
trackEntryPool.Free(trackEntry); // Pooling
|
||||||
break;
|
break;
|
||||||
case EventType.Complete:
|
case EventType.Complete:
|
||||||
trackEntry.OnComplete();
|
trackEntry.OnComplete();
|
||||||
@ -921,4 +941,57 @@ namespace Spine {
|
|||||||
eventQueueEntries.Clear();
|
eventQueueEntries.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Pool<T> where T : class, new() {
|
||||||
|
public readonly int max;
|
||||||
|
readonly Stack<T> freeObjects;
|
||||||
|
|
||||||
|
public int Count { get { return freeObjects.Count; } }
|
||||||
|
public int Peak { get; private set; }
|
||||||
|
|
||||||
|
public Pool (int initialCapacity = 16, int max = int.MaxValue) {
|
||||||
|
freeObjects = new Stack<T>(initialCapacity);
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Obtain () {
|
||||||
|
return freeObjects.Count == 0 ? new T() : freeObjects.Pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free (T obj) {
|
||||||
|
if (obj == null) throw new ArgumentNullException("obj", "obj cannot be null");
|
||||||
|
if (freeObjects.Count < max) {
|
||||||
|
freeObjects.Push(obj);
|
||||||
|
Peak = Math.Max(Peak, freeObjects.Count);
|
||||||
|
}
|
||||||
|
Reset(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// protected void FreeAll (List<T> objects) {
|
||||||
|
// if (objects == null) throw new ArgumentNullException("objects", "objects cannot be null.");
|
||||||
|
// var freeObjects = this.freeObjects;
|
||||||
|
// int max = this.max;
|
||||||
|
// for (int i = 0; i < objects.Count; i++) {
|
||||||
|
// T obj = objects[i];
|
||||||
|
// if (obj == null) continue;
|
||||||
|
// if (freeObjects.Count < max) freeObjects.Push(obj);
|
||||||
|
// Reset(obj);
|
||||||
|
// }
|
||||||
|
// Peak = Math.Max(Peak, freeObjects.Count);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void Clear () {
|
||||||
|
freeObjects.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Reset (T obj) {
|
||||||
|
var poolable = obj as IPoolable;
|
||||||
|
if (poolable != null) poolable.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IPoolable {
|
||||||
|
void Reset ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,7 +134,7 @@ public class AnimationStateTests {
|
|||||||
expect(0, "end", 1, 1.1f), //
|
expect(0, "end", 1, 1.1f), //
|
||||||
expect(0, "dispose", 1, 1.1f) //
|
expect(0, "dispose", 1, 1.1f) //
|
||||||
);
|
);
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false).setTrackEnd(1);
|
||||||
run(0.1f, 1000, null);
|
run(0.1f, 1000, null);
|
||||||
|
|
||||||
setup("1/60 time step, dispose queued", // 2
|
setup("1/60 time step, dispose queued", // 2
|
||||||
@ -160,7 +160,7 @@ public class AnimationStateTests {
|
|||||||
state.addAnimation(0, "events1", false, 0);
|
state.addAnimation(0, "events1", false, 0);
|
||||||
state.addAnimation(0, "events0", false, 0);
|
state.addAnimation(0, "events0", false, 0);
|
||||||
state.addAnimation(0, "events1", false, 0);
|
state.addAnimation(0, "events1", false, 0);
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false).setTrackEnd(1);
|
||||||
run(1 / 60f, 1000, null);
|
run(1 / 60f, 1000, null);
|
||||||
|
|
||||||
setup("30 time step", // 3
|
setup("30 time step", // 3
|
||||||
@ -172,7 +172,7 @@ public class AnimationStateTests {
|
|||||||
expect(0, "end", 30, 60), //
|
expect(0, "end", 30, 60), //
|
||||||
expect(0, "dispose", 30, 60) //
|
expect(0, "dispose", 30, 60) //
|
||||||
);
|
);
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false).setTrackEnd(1);
|
||||||
run(30, 1000, null);
|
run(30, 1000, null);
|
||||||
|
|
||||||
setup("1 time step", // 4
|
setup("1 time step", // 4
|
||||||
@ -184,7 +184,7 @@ public class AnimationStateTests {
|
|||||||
expect(0, "end", 1, 2), //
|
expect(0, "end", 1, 2), //
|
||||||
expect(0, "dispose", 1, 2) //
|
expect(0, "dispose", 1, 2) //
|
||||||
);
|
);
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false).setTrackEnd(1);
|
||||||
run(1, 1.01f, null);
|
run(1, 1.01f, null);
|
||||||
|
|
||||||
setup("interrupt", // 5
|
setup("interrupt", // 5
|
||||||
@ -220,7 +220,7 @@ public class AnimationStateTests {
|
|||||||
);
|
);
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false);
|
||||||
state.addAnimation(0, "events1", false, 0);
|
state.addAnimation(0, "events1", false, 0);
|
||||||
state.addAnimation(0, "events0", false, 0);
|
state.addAnimation(0, "events0", false, 0).setTrackEnd(1);
|
||||||
run(0.1f, 4f, null);
|
run(0.1f, 4f, null);
|
||||||
|
|
||||||
setup("interrupt with delay", // 6
|
setup("interrupt with delay", // 6
|
||||||
@ -242,7 +242,7 @@ public class AnimationStateTests {
|
|||||||
expect(1, "dispose", 1, 1.6f) //
|
expect(1, "dispose", 1, 1.6f) //
|
||||||
);
|
);
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false);
|
||||||
state.addAnimation(0, "events1", false, 0.5f);
|
state.addAnimation(0, "events1", false, 0.5f).setTrackEnd(1);
|
||||||
run(0.1f, 1000, null);
|
run(0.1f, 1000, null);
|
||||||
|
|
||||||
setup("interrupt with delay and mix time", // 7
|
setup("interrupt with delay and mix time", // 7
|
||||||
@ -268,7 +268,7 @@ public class AnimationStateTests {
|
|||||||
);
|
);
|
||||||
stateData.setMix("events0", "events1", 0.7f);
|
stateData.setMix("events0", "events1", 0.7f);
|
||||||
state.setAnimation(0, "events0", true);
|
state.setAnimation(0, "events0", true);
|
||||||
state.addAnimation(0, "events1", false, 0.9f);
|
state.addAnimation(0, "events1", false, 0.9f).setTrackEnd(1);
|
||||||
run(0.1f, 1000, null);
|
run(0.1f, 1000, null);
|
||||||
|
|
||||||
setup("animation 0 events do not fire during mix", // 8
|
setup("animation 0 events do not fire during mix", // 8
|
||||||
@ -291,7 +291,7 @@ public class AnimationStateTests {
|
|||||||
);
|
);
|
||||||
stateData.setDefaultMix(0.7f);
|
stateData.setDefaultMix(0.7f);
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false);
|
||||||
state.addAnimation(0, "events1", false, 0.4f);
|
state.addAnimation(0, "events1", false, 0.4f).setTrackEnd(1);
|
||||||
run(0.1f, 1000, null);
|
run(0.1f, 1000, null);
|
||||||
|
|
||||||
setup("event threshold, some animation 0 events fire during mix", // 9
|
setup("event threshold, some animation 0 events fire during mix", // 9
|
||||||
@ -317,7 +317,7 @@ public class AnimationStateTests {
|
|||||||
);
|
);
|
||||||
stateData.setMix("events0", "events1", 0.7f);
|
stateData.setMix("events0", "events1", 0.7f);
|
||||||
state.setAnimation(0, "events0", false).setEventThreshold(0.5f);
|
state.setAnimation(0, "events0", false).setEventThreshold(0.5f);
|
||||||
state.addAnimation(0, "events1", false, 0.4f);
|
state.addAnimation(0, "events1", false, 0.4f).setTrackEnd(1);
|
||||||
run(0.1f, 1000, null);
|
run(0.1f, 1000, null);
|
||||||
|
|
||||||
setup("event threshold, all animation 0 events fire during mix", // 10
|
setup("event threshold, all animation 0 events fire during mix", // 10
|
||||||
@ -344,7 +344,9 @@ public class AnimationStateTests {
|
|||||||
expect(1, "dispose", 1, 1.9f) //
|
expect(1, "dispose", 1, 1.9f) //
|
||||||
);
|
);
|
||||||
state.setAnimation(0, "events0", true).setEventThreshold(1);
|
state.setAnimation(0, "events0", true).setEventThreshold(1);
|
||||||
state.addAnimation(0, "events1", false, 0.8f).setMixDuration(0.7f);
|
entry = state.addAnimation(0, "events1", false, 0.8f);
|
||||||
|
entry.setMixDuration(0.7f);
|
||||||
|
entry.setTrackEnd(1);
|
||||||
run(0.1f, 1000, null);
|
run(0.1f, 1000, null);
|
||||||
|
|
||||||
setup("looping", // 11
|
setup("looping", // 11
|
||||||
@ -393,7 +395,7 @@ public class AnimationStateTests {
|
|||||||
expect(1, "dispose", 1, 3.1f) //
|
expect(1, "dispose", 1, 3.1f) //
|
||||||
);
|
);
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false);
|
||||||
state.addAnimation(0, "events1", false, 2);
|
state.addAnimation(0, "events1", false, 2).setTrackEnd(1);
|
||||||
run(0.1f, 4f, null);
|
run(0.1f, 4f, null);
|
||||||
|
|
||||||
setup("interrupt animation after first loop complete", // 13
|
setup("interrupt animation after first loop complete", // 13
|
||||||
@ -424,7 +426,7 @@ public class AnimationStateTests {
|
|||||||
state.setAnimation(0, "events0", true);
|
state.setAnimation(0, "events0", true);
|
||||||
run(0.1f, 6, new TestListener() {
|
run(0.1f, 6, new TestListener() {
|
||||||
public void frame (float time) {
|
public void frame (float time) {
|
||||||
if (MathUtils.isEqual(time, 1.4f)) state.addAnimation(0, "events1", false, 0);
|
if (MathUtils.isEqual(time, 1.4f)) state.addAnimation(0, "events1", false, 0).setTrackEnd(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -437,7 +439,7 @@ public class AnimationStateTests {
|
|||||||
expect(0, "end", 1, 1.1f), //
|
expect(0, "end", 1, 1.1f), //
|
||||||
expect(0, "dispose", 1, 1.1f) //
|
expect(0, "dispose", 1, 1.1f) //
|
||||||
);
|
);
|
||||||
state.addAnimation(0, "events0", false, 0);
|
state.addAnimation(0, "events0", false, 0).setTrackEnd(1);
|
||||||
run(0.1f, 1.9f, null);
|
run(0.1f, 1.9f, null);
|
||||||
|
|
||||||
setup("end time beyond non-looping animation duration", // 15
|
setup("end time beyond non-looping animation duration", // 15
|
||||||
@ -495,6 +497,7 @@ public class AnimationStateTests {
|
|||||||
entry.setAnimationStart(0.2f);
|
entry.setAnimationStart(0.2f);
|
||||||
entry.setAnimationLast(0.2f);
|
entry.setAnimationLast(0.2f);
|
||||||
entry.setAnimationEnd(0.8f);
|
entry.setAnimationEnd(0.8f);
|
||||||
|
entry.setTrackEnd(1);
|
||||||
run(0.1f, 1.8f, null);
|
run(0.1f, 1.8f, null);
|
||||||
|
|
||||||
setup("mix out looping with animation start and end", // 19
|
setup("mix out looping with animation start and end", // 19
|
||||||
@ -524,7 +527,9 @@ public class AnimationStateTests {
|
|||||||
entry.setAnimationLast(0.2f);
|
entry.setAnimationLast(0.2f);
|
||||||
entry.setAnimationEnd(0.8f);
|
entry.setAnimationEnd(0.8f);
|
||||||
entry.setEventThreshold(1);
|
entry.setEventThreshold(1);
|
||||||
state.addAnimation(0, "events1", false, 0.7f).setMixDuration(0.7f);
|
entry = state.addAnimation(0, "events1", false, 0.7f);
|
||||||
|
entry.setMixDuration(0.7f);
|
||||||
|
entry.setTrackEnd(1);
|
||||||
run(0.1f, 20, null);
|
run(0.1f, 20, null);
|
||||||
|
|
||||||
setup("setAnimation with track entry mix", // 20
|
setup("setAnimation with track entry mix", // 20
|
||||||
@ -552,7 +557,11 @@ public class AnimationStateTests {
|
|||||||
state.setAnimation(0, "events0", true);
|
state.setAnimation(0, "events0", true);
|
||||||
run(0.1f, 1000, new TestListener() {
|
run(0.1f, 1000, new TestListener() {
|
||||||
public void frame (float time) {
|
public void frame (float time) {
|
||||||
if (MathUtils.isEqual(time, 1f)) state.setAnimation(0, "events1", false).setMixDuration(0.7f);
|
if (MathUtils.isEqual(time, 1f)) {
|
||||||
|
TrackEntry entry = state.setAnimation(0, "events1", false);
|
||||||
|
entry.setMixDuration(0.7f);
|
||||||
|
entry.setTrackEnd(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -593,7 +602,7 @@ public class AnimationStateTests {
|
|||||||
public void frame (float time) {
|
public void frame (float time) {
|
||||||
if (MathUtils.isEqual(time, 0.8f)) {
|
if (MathUtils.isEqual(time, 0.8f)) {
|
||||||
state.setAnimation(0, "events0", false); // First should be ignored.
|
state.setAnimation(0, "events0", false); // First should be ignored.
|
||||||
state.setAnimation(0, "events2", false);
|
state.setAnimation(0, "events2", false).setTrackEnd(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -655,7 +664,7 @@ public class AnimationStateTests {
|
|||||||
}
|
}
|
||||||
if (MathUtils.isEqual(time, 0.4f)) {
|
if (MathUtils.isEqual(time, 0.4f)) {
|
||||||
state.setAnimation(0, "events1", false); // First should be ignored.
|
state.setAnimation(0, "events1", false); // First should be ignored.
|
||||||
state.setAnimation(0, "events0", false);
|
state.setAnimation(0, "events0", false).setTrackEnd(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -669,7 +678,7 @@ public class AnimationStateTests {
|
|||||||
expect(0, "end", 1, 6.1f), //
|
expect(0, "end", 1, 6.1f), //
|
||||||
expect(0, "dispose", 1, 6.1f) //
|
expect(0, "dispose", 1, 6.1f) //
|
||||||
);
|
);
|
||||||
state.addAnimation(0, "events0", false, 5);
|
state.addAnimation(0, "events0", false, 5).setTrackEnd(1);
|
||||||
run(0.1f, 10, null);
|
run(0.1f, 10, null);
|
||||||
|
|
||||||
setup("setAnimation during AnimationStateListener"); // 24
|
setup("setAnimation during AnimationStateListener"); // 24
|
||||||
@ -700,7 +709,7 @@ public class AnimationStateTests {
|
|||||||
});
|
});
|
||||||
state.addAnimation(0, "events0", false, 0);
|
state.addAnimation(0, "events0", false, 0);
|
||||||
state.addAnimation(0, "events1", false, 0);
|
state.addAnimation(0, "events1", false, 0);
|
||||||
state.setAnimation(1, "events1", false);
|
state.setAnimation(1, "events1", false).setTrackEnd(1);
|
||||||
run(0.1f, 10, null);
|
run(0.1f, 10, null);
|
||||||
|
|
||||||
setup("clearTrack", // 25
|
setup("clearTrack", // 25
|
||||||
@ -710,7 +719,7 @@ public class AnimationStateTests {
|
|||||||
expect(0, "end", 0.7f, 0.7f), //
|
expect(0, "end", 0.7f, 0.7f), //
|
||||||
expect(0, "dispose", 0.7f, 0.7f) //
|
expect(0, "dispose", 0.7f, 0.7f) //
|
||||||
);
|
);
|
||||||
state.addAnimation(0, "events0", false, 0);
|
state.addAnimation(0, "events0", false, 0).setTrackEnd(1);
|
||||||
run(0.1f, 10, new TestListener() {
|
run(0.1f, 10, new TestListener() {
|
||||||
public void frame (float time) {
|
public void frame (float time) {
|
||||||
if (MathUtils.isEqual(time, 0.7f)) state.clearTrack(0);
|
if (MathUtils.isEqual(time, 0.7f)) state.clearTrack(0);
|
||||||
@ -732,7 +741,7 @@ public class AnimationStateTests {
|
|||||||
expect(-1, "end", 0.2f, 1), //
|
expect(-1, "end", 0.2f, 1), //
|
||||||
expect(-1, "dispose", 0.2f, 1) //
|
expect(-1, "dispose", 0.2f, 1) //
|
||||||
);
|
);
|
||||||
state.addAnimation(0, "events0", false, 0);
|
state.addAnimation(0, "events0", false, 0).setTrackEnd(1);
|
||||||
run(0.1f, 10, new TestListener() {
|
run(0.1f, 10, new TestListener() {
|
||||||
public void frame (float time) {
|
public void frame (float time) {
|
||||||
if (MathUtils.isEqual(time, 0.7f)) state.setEmptyAnimation(0, 0);
|
if (MathUtils.isEqual(time, 0.7f)) state.setEmptyAnimation(0, 0);
|
||||||
@ -768,7 +777,7 @@ public class AnimationStateTests {
|
|||||||
});
|
});
|
||||||
state.addAnimation(0, "events0", false, 0);
|
state.addAnimation(0, "events0", false, 0);
|
||||||
state.addAnimation(0, "events1", false, 0);
|
state.addAnimation(0, "events1", false, 0);
|
||||||
state.setAnimation(1, "events1", false);
|
state.setAnimation(1, "events1", false).setTrackEnd(1);
|
||||||
run(0.1f, 10, null);
|
run(0.1f, 10, null);
|
||||||
if (counter.get() != 15082016) {
|
if (counter.get() != 15082016) {
|
||||||
log("TEST 26 FAILED! " + counter);
|
log("TEST 26 FAILED! " + counter);
|
||||||
|
|||||||
@ -185,6 +185,7 @@ public class AnimationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
queueEvents(current, animationTime);
|
queueEvents(current, animationTime);
|
||||||
|
events.clear();
|
||||||
current.nextAnimationLast = animationTime;
|
current.nextAnimationLast = animationTime;
|
||||||
current.nextTrackLast = current.trackTime;
|
current.nextTrackLast = current.trackTime;
|
||||||
}
|
}
|
||||||
@ -230,7 +231,8 @@ public class AnimationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
queueEvents(from, animationTime);
|
if (entry.mixDuration > 0) queueEvents(from, animationTime);
|
||||||
|
this.events.clear();
|
||||||
from.nextAnimationLast = animationTime;
|
from.nextAnimationLast = animationTime;
|
||||||
from.nextTrackLast = from.trackTime;
|
from.nextTrackLast = from.trackTime;
|
||||||
|
|
||||||
@ -330,7 +332,6 @@ public class AnimationState {
|
|||||||
if (event.time < animationStart) continue; // Discard events outside animation start/end.
|
if (event.time < animationStart) continue; // Discard events outside animation start/end.
|
||||||
queue.event(entry, events.get(i));
|
queue.event(entry, events.get(i));
|
||||||
}
|
}
|
||||||
events.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Removes all animations from all tracks, leaving skeletons in their previous pose.
|
/** Removes all animations from all tracks, leaving skeletons in their previous pose.
|
||||||
@ -385,7 +386,7 @@ public class AnimationState {
|
|||||||
from.timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in.
|
from.timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in.
|
||||||
|
|
||||||
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
||||||
if (from.mixingFrom != null) current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
if (from.mixingFrom != null && from.mixDuration > 0) current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.start(current);
|
queue.start(current);
|
||||||
@ -539,7 +540,7 @@ public class AnimationState {
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? Integer.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = Float.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
|
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
@ -752,10 +753,10 @@ public class AnimationState {
|
|||||||
this.trackTime = trackTime;
|
this.trackTime = trackTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The track time in seconds when this animation will be removed from the track. Defaults to the animation
|
/** The track time in seconds when this animation will be removed from the track. Defaults to the highest possible float
|
||||||
* {@link Animation#duration} for non-looping animations and the highest float possible for looping animations. If the track
|
* value, meaning the animation will be applied until a new animation is set or the track is cleared. If the track end time
|
||||||
* end time is reached, no other animations are queued for playback, and mixing from any previous animations is complete,
|
* is reached, no other animations are queued for playback, and mixing from any previous animations is complete, then the
|
||||||
* then the properties keyed by the animation are set to the setup pose and the track is cleared.
|
* properties keyed by the animation are set to the setup pose and the track is cleared.
|
||||||
* <p>
|
* <p>
|
||||||
* It may be desired to use {@link AnimationState#addEmptyAnimation(int, float, float)} to mix the properties back to the
|
* It may be desired to use {@link AnimationState#addEmptyAnimation(int, float, float)} to mix the properties back to the
|
||||||
* setup pose over time, rather than have it happen instantly. */
|
* setup pose over time, rather than have it happen instantly. */
|
||||||
|
|||||||
@ -541,7 +541,7 @@ function AnimationState:setCurrent (index, current, interrupt)
|
|||||||
from.timelinesRotation = {};
|
from.timelinesRotation = {};
|
||||||
|
|
||||||
-- If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
-- If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
||||||
if from.mixingFrom then current.mixAlpha = current.mixAlpha * math_min(from.mixTime / from.mixDuration, 1) end
|
if from.mixingFrom and from.mixDuration > 0 then current.mixAlpha = current.mixAlpha * math_min(from.mixTime / from.mixDuration, 1) end
|
||||||
end
|
end
|
||||||
|
|
||||||
queue:start(current)
|
queue:start(current)
|
||||||
@ -665,11 +665,7 @@ function AnimationState:trackEntry (trackIndex, animation, loop, last)
|
|||||||
entry.trackTime = 0
|
entry.trackTime = 0
|
||||||
entry.trackLast = -1
|
entry.trackLast = -1
|
||||||
entry.nextTrackLast = -1
|
entry.nextTrackLast = -1
|
||||||
if loop then
|
entry.trackEnd = 999999999
|
||||||
entry.trackEnd = 999999999
|
|
||||||
else
|
|
||||||
entry.trackEnd = entry.animationEnd
|
|
||||||
end
|
|
||||||
entry.timeScale = 1
|
entry.timeScale = 1
|
||||||
|
|
||||||
entry.alpha = 1
|
entry.alpha = 1
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -75,8 +75,8 @@ setup a development environment, follow these steps.
|
|||||||
* **WebGL**: `tsc -w -p tsconfig.webgl.json`, builds `core/src` and `webgl/src`, outputs `build/spine-webgl.js|d.ts|js.map`
|
* **WebGL**: `tsc -w -p tsconfig.webgl.json`, builds `core/src` and `webgl/src`, outputs `build/spine-webgl.js|d.ts|js.map`
|
||||||
* **Canvas**: `tsc -w -p tsconfig.canvas.json`, builds `core/src` and `canvas/src`, outputs `build/spine-canvas.js|d.ts|js.map`
|
* **Canvas**: `tsc -w -p tsconfig.canvas.json`, builds `core/src` and `canvas/src`, outputs `build/spine-canvas.js|d.ts|js.map`
|
||||||
* **THREE.JS**: `tsc -w -p tsconfig.threejs.json`, builds `core/src` and `threejs/src`, outputs `build/spine-threejs.js|d.ts|js.map`
|
* **THREE.JS**: `tsc -w -p tsconfig.threejs.json`, builds `core/src` and `threejs/src`, outputs `build/spine-threejs.js|d.ts|js.map`
|
||||||
* **Widget**: `tsc -w -p tsconfig.widget.json`, builds `core/src` and `widget/src`, outputs `build/spine-widget.js|d.ts|js.map`
|
* **Widget**: `tsc -w -p tsconfig.widget.json`, builds `core/src` and `widget/src`, outputs `build/spine-widget.js|d.ts|js.map`
|
||||||
6. Open the `spine-ts` folder in Visual Studio Code. VS Code will use the `tsconfig.json` file all source files from core and all
|
6. Open the `spine-ts` folder in Visual Studio Code. VS Code will use the `tsconfig.json` file all source files from core and all
|
||||||
backends for your development pleasure. The actual JavaScript output is still created by the command line TypeScript compiler process from the previous step.
|
backends for your development pleasure. The actual JavaScript output is still created by the command line TypeScript compiler process from the previous step.
|
||||||
|
|
||||||
Each backend contains an `example/` folder with an `index.html` file that demonstrates the respective backend. For development, we
|
Each backend contains an `example/` folder with an `index.html` file that demonstrates the respective backend. For development, we
|
||||||
@ -90,7 +90,7 @@ python -m SimpleHTTPServer
|
|||||||
Then navigate to `http://localhost:8000/webgl/example`, `http://localhost:8000/canvas/example`, `http://localhost:8000/threejs/example` or `http://localhost:8000/widget/example`
|
Then navigate to `http://localhost:8000/webgl/example`, `http://localhost:8000/canvas/example`, `http://localhost:8000/threejs/example` or `http://localhost:8000/widget/example`
|
||||||
|
|
||||||
### Using the Widget
|
### Using the Widget
|
||||||
To easily display Spine animations on your website, you can use the spine-ts Widget backend.
|
To easily display Spine animations on your website, you can use the spine-ts Widget backend.
|
||||||
|
|
||||||
1. Export your Spine animation with a texture atlas and put the resulting `.json`, `.atlas` and `.png` files on your server.
|
1. Export your Spine animation with a texture atlas and put the resulting `.json`, `.atlas` and `.png` files on your server.
|
||||||
2. Copy the `build/spine-widget.js` file to your server and include it on your website `<script src="spine-widget.js"></script>`, adjusting the src to match the location of the file on your server.
|
2. Copy the `build/spine-widget.js` file to your server and include it on your website `<script src="spine-widget.js"></script>`, adjusting the src to match the location of the file on your server.
|
||||||
@ -114,7 +114,7 @@ To specify the configuration of a Spine Widget via HTML, you can use these HTML
|
|||||||
* `data-fit-to-canvas`: optional, whether to fit the animation to the canvas size or not. Defaults to `true` if omitted, in which case `data-scale`, `data-x` and `data-y` are irrelevant. This setting calculates the setup pose bounding box using the specified skin to center and scale the animation on the canvas.
|
* `data-fit-to-canvas`: optional, whether to fit the animation to the canvas size or not. Defaults to `true` if omitted, in which case `data-scale`, `data-x` and `data-y` are irrelevant. This setting calculates the setup pose bounding box using the specified skin to center and scale the animation on the canvas.
|
||||||
* `data-background-color`: optional, the background color to use. Defaults to `#000000` if omitted.
|
* `data-background-color`: optional, the background color to use. Defaults to `#000000` if omitted.
|
||||||
* `data-premultiplied-alpha`: optional, whether the atlas pages use premultiplied alpha or not. Defaults to `false` if omitted.
|
* `data-premultiplied-alpha`: optional, whether the atlas pages use premultiplied alpha or not. Defaults to `false` if omitted.
|
||||||
* `data-debug`: optional, whether to show debug information such as bones, attachments, etc. Defaults to `false` if omitted.
|
* `data-debug`: optional, whether to show debug information such as bones, attachments, etc. Defaults to `false` if omitted.
|
||||||
|
|
||||||
You can specify these as attribuets on the HTML element like this:
|
You can specify these as attribuets on the HTML element like this:
|
||||||
|
|
||||||
@ -139,12 +139,12 @@ Then create a new `spine.SpineWidget`, providing a [`SpineWidgetConfiguration`](
|
|||||||
```JavaScript
|
```JavaScript
|
||||||
new spine.SpineWidget("my-widget", {
|
new spine.SpineWidget("my-widget", {
|
||||||
json: "assets/spineboy.json",
|
json: "assets/spineboy.json",
|
||||||
atlas: "assets/spineboy.atlas",
|
atlas: "assets/spineboy.atlas",
|
||||||
animation: "run",
|
animation: "run",
|
||||||
backgroundColor: "#000000",
|
backgroundColor: "#000000",
|
||||||
success: function (widget) {
|
success: function (widget) {
|
||||||
var animIndex = 0;
|
var animIndex = 0;
|
||||||
widget.canvas.onclick = function () {
|
widget.canvas.onclick = function () {
|
||||||
animIndex++;
|
animIndex++;
|
||||||
let animations = widget.skeleton.data.animations;
|
let animations = widget.skeleton.data.animations;
|
||||||
if (animIndex >= animations.length) animIndex = 0;
|
if (animIndex >= animations.length) animIndex = 0;
|
||||||
@ -160,6 +160,7 @@ The configuration object has the following fields:
|
|||||||
* `atlas`: required, path to the `.atlas` file, absolute or relative, e.g. "assets/animation.atlas"
|
* `atlas`: required, path to the `.atlas` file, absolute or relative, e.g. "assets/animation.atlas"
|
||||||
* `animation`: required, the name of the animation to play back
|
* `animation`: required, the name of the animation to play back
|
||||||
* `imagesPath`: optional, the location of images on the server to load atlas pages from. If omitted, atlas `.png` page files are loaded relative to the `.atlas` file.
|
* `imagesPath`: optional, the location of images on the server to load atlas pages from. If omitted, atlas `.png` page files are loaded relative to the `.atlas` file.
|
||||||
|
* `atlasPages`: optional, the list of atlas page images, e.g. `atlasPages: ["assets/page1.png", "assets/page2.png"]` when using code, or `data-atlas-pages="assets/page1.png,assets/page2.png"` on case of HTML instantiation. Use this if you have a multi-page atlas. If ommited, only one atlas page image is loaded based on the atlas file name, replacing `.atlas` with `.png`.
|
||||||
* `skin`: optional, the name of the skin to use. Defaults to `default` if omitted.
|
* `skin`: optional, the name of the skin to use. Defaults to `default` if omitted.
|
||||||
* `loop`: optional, whether to loop the animation or not. Defaults to `true` if omitted.
|
* `loop`: optional, whether to loop the animation or not. Defaults to `true` if omitted.
|
||||||
* `scale`: optional, the scaling factor to apply when loading the `.json` file. Defaults to `1` if omitted. Irrelevant if `data-fit-to-canavs` is `true`.
|
* `scale`: optional, the scaling factor to apply when loading the `.json` file. Defaults to `1` if omitted. Irrelevant if `data-fit-to-canavs` is `true`.
|
||||||
|
|||||||
1
spine-ts/build/spine-all.d.ts
vendored
1
spine-ts/build/spine-all.d.ts
vendored
@ -1543,6 +1543,7 @@ declare module spine {
|
|||||||
atlas: string;
|
atlas: string;
|
||||||
animation: string;
|
animation: string;
|
||||||
imagesPath: string;
|
imagesPath: string;
|
||||||
|
atlasPages: string[];
|
||||||
skin: string;
|
skin: string;
|
||||||
loop: boolean;
|
loop: boolean;
|
||||||
scale: number;
|
scale: number;
|
||||||
|
|||||||
@ -1568,7 +1568,7 @@ var spine;
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
from.timelinesRotation.length = 0;
|
from.timelinesRotation.length = 0;
|
||||||
if (from.mixingFrom != null)
|
if (from.mixingFrom != null && from.mixDuration > 0)
|
||||||
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
this.queue.start(current);
|
this.queue.start(current);
|
||||||
@ -1680,7 +1680,7 @@ var spine;
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? Number.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = Number.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
entry.mixAlpha = 1;
|
entry.mixAlpha = 1;
|
||||||
@ -7899,7 +7899,14 @@ var spine;
|
|||||||
var assets = this.assetManager = new spine.webgl.AssetManager(gl);
|
var assets = this.assetManager = new spine.webgl.AssetManager(gl);
|
||||||
assets.loadText(config.atlas);
|
assets.loadText(config.atlas);
|
||||||
assets.loadText(config.json);
|
assets.loadText(config.json);
|
||||||
assets.loadTexture(config.atlas.replace(".atlas", ".png"));
|
if (config.atlasPages == null) {
|
||||||
|
assets.loadTexture(config.atlas.replace(".atlas", ".png"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var i = 0; i < config.atlasPages.length; i++) {
|
||||||
|
assets.loadTexture(config.atlasPages[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
requestAnimationFrame(function () { _this.load(); });
|
requestAnimationFrame(function () { _this.load(); });
|
||||||
}
|
}
|
||||||
SpineWidget.prototype.validateConfig = function (config) {
|
SpineWidget.prototype.validateConfig = function (config) {
|
||||||
@ -8082,6 +8089,8 @@ var spine;
|
|||||||
config.animation = widget.getAttribute("data-animation");
|
config.animation = widget.getAttribute("data-animation");
|
||||||
if (widget.getAttribute("data-images-path"))
|
if (widget.getAttribute("data-images-path"))
|
||||||
config.imagesPath = widget.getAttribute("data-images-path");
|
config.imagesPath = widget.getAttribute("data-images-path");
|
||||||
|
if (widget.getAttribute("data-atlas-pages"))
|
||||||
|
config.atlasPages = widget.getAttribute("data-atlas-pages").split(",");
|
||||||
if (widget.getAttribute("data-skin"))
|
if (widget.getAttribute("data-skin"))
|
||||||
config.skin = widget.getAttribute("data-skin");
|
config.skin = widget.getAttribute("data-skin");
|
||||||
if (widget.getAttribute("data-loop"))
|
if (widget.getAttribute("data-loop"))
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1568,7 +1568,7 @@ var spine;
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
from.timelinesRotation.length = 0;
|
from.timelinesRotation.length = 0;
|
||||||
if (from.mixingFrom != null)
|
if (from.mixingFrom != null && from.mixDuration > 0)
|
||||||
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
this.queue.start(current);
|
this.queue.start(current);
|
||||||
@ -1680,7 +1680,7 @@ var spine;
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? Number.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = Number.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
entry.mixAlpha = 1;
|
entry.mixAlpha = 1;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1221,7 +1221,7 @@ var spine;
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
from.timelinesRotation.length = 0;
|
from.timelinesRotation.length = 0;
|
||||||
if (from.mixingFrom != null)
|
if (from.mixingFrom != null && from.mixDuration > 0)
|
||||||
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
this.queue.start(current);
|
this.queue.start(current);
|
||||||
@ -1333,7 +1333,7 @@ var spine;
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? Number.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = Number.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
entry.mixAlpha = 1;
|
entry.mixAlpha = 1;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1221,7 +1221,7 @@ var spine;
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
from.timelinesRotation.length = 0;
|
from.timelinesRotation.length = 0;
|
||||||
if (from.mixingFrom != null)
|
if (from.mixingFrom != null && from.mixDuration > 0)
|
||||||
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
this.queue.start(current);
|
this.queue.start(current);
|
||||||
@ -1333,7 +1333,7 @@ var spine;
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? Number.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = Number.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
entry.mixAlpha = 1;
|
entry.mixAlpha = 1;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1221,7 +1221,7 @@ var spine;
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
from.timelinesRotation.length = 0;
|
from.timelinesRotation.length = 0;
|
||||||
if (from.mixingFrom != null)
|
if (from.mixingFrom != null && from.mixDuration > 0)
|
||||||
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
this.queue.start(current);
|
this.queue.start(current);
|
||||||
@ -1333,7 +1333,7 @@ var spine;
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? Number.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = Number.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
entry.mixAlpha = 1;
|
entry.mixAlpha = 1;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
1
spine-ts/build/spine-widget.d.ts
vendored
1
spine-ts/build/spine-widget.d.ts
vendored
@ -1473,6 +1473,7 @@ declare module spine {
|
|||||||
atlas: string;
|
atlas: string;
|
||||||
animation: string;
|
animation: string;
|
||||||
imagesPath: string;
|
imagesPath: string;
|
||||||
|
atlasPages: string[];
|
||||||
skin: string;
|
skin: string;
|
||||||
loop: boolean;
|
loop: boolean;
|
||||||
scale: number;
|
scale: number;
|
||||||
|
|||||||
@ -1221,7 +1221,7 @@ var spine;
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
from.timelinesRotation.length = 0;
|
from.timelinesRotation.length = 0;
|
||||||
if (from.mixingFrom != null)
|
if (from.mixingFrom != null && from.mixDuration > 0)
|
||||||
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
this.queue.start(current);
|
this.queue.start(current);
|
||||||
@ -1333,7 +1333,7 @@ var spine;
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? Number.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = Number.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
entry.mixAlpha = 1;
|
entry.mixAlpha = 1;
|
||||||
@ -7478,7 +7478,14 @@ var spine;
|
|||||||
var assets = this.assetManager = new spine.webgl.AssetManager(gl);
|
var assets = this.assetManager = new spine.webgl.AssetManager(gl);
|
||||||
assets.loadText(config.atlas);
|
assets.loadText(config.atlas);
|
||||||
assets.loadText(config.json);
|
assets.loadText(config.json);
|
||||||
assets.loadTexture(config.atlas.replace(".atlas", ".png"));
|
if (config.atlasPages == null) {
|
||||||
|
assets.loadTexture(config.atlas.replace(".atlas", ".png"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var i = 0; i < config.atlasPages.length; i++) {
|
||||||
|
assets.loadTexture(config.atlasPages[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
requestAnimationFrame(function () { _this.load(); });
|
requestAnimationFrame(function () { _this.load(); });
|
||||||
}
|
}
|
||||||
SpineWidget.prototype.validateConfig = function (config) {
|
SpineWidget.prototype.validateConfig = function (config) {
|
||||||
@ -7661,6 +7668,8 @@ var spine;
|
|||||||
config.animation = widget.getAttribute("data-animation");
|
config.animation = widget.getAttribute("data-animation");
|
||||||
if (widget.getAttribute("data-images-path"))
|
if (widget.getAttribute("data-images-path"))
|
||||||
config.imagesPath = widget.getAttribute("data-images-path");
|
config.imagesPath = widget.getAttribute("data-images-path");
|
||||||
|
if (widget.getAttribute("data-atlas-pages"))
|
||||||
|
config.atlasPages = widget.getAttribute("data-atlas-pages").split(",");
|
||||||
if (widget.getAttribute("data-skin"))
|
if (widget.getAttribute("data-skin"))
|
||||||
config.skin = widget.getAttribute("data-skin");
|
config.skin = widget.getAttribute("data-skin");
|
||||||
if (widget.getAttribute("data-loop"))
|
if (widget.getAttribute("data-loop"))
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -349,7 +349,7 @@ module spine {
|
|||||||
from.timelinesRotation.length = 0;
|
from.timelinesRotation.length = 0;
|
||||||
|
|
||||||
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
||||||
if (from.mixingFrom != null) current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
if (from.mixingFrom != null && from.mixDuration > 0) current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.queue.start(current);
|
this.queue.start(current);
|
||||||
@ -469,7 +469,7 @@ module spine {
|
|||||||
entry.trackTime = 0;
|
entry.trackTime = 0;
|
||||||
entry.trackLast = -1;
|
entry.trackLast = -1;
|
||||||
entry.nextTrackLast = -1;
|
entry.nextTrackLast = -1;
|
||||||
entry.trackEnd = loop ? Number.MAX_VALUE : entry.animationEnd;
|
entry.trackEnd = Number.MAX_VALUE;
|
||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
|
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
|
|||||||
@ -80,7 +80,13 @@ module spine {
|
|||||||
let assets = this.assetManager = new spine.webgl.AssetManager(gl);
|
let assets = this.assetManager = new spine.webgl.AssetManager(gl);
|
||||||
assets.loadText(config.atlas);
|
assets.loadText(config.atlas);
|
||||||
assets.loadText(config.json);
|
assets.loadText(config.json);
|
||||||
assets.loadTexture(config.atlas.replace(".atlas", ".png"));
|
if (config.atlasPages == null) {
|
||||||
|
assets.loadTexture(config.atlas.replace(".atlas", ".png"));
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < config.atlasPages.length; i++) {
|
||||||
|
assets.loadTexture(config.atlasPages[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
requestAnimationFrame(() => { this.load(); });
|
requestAnimationFrame(() => { this.load(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +270,7 @@ module spine {
|
|||||||
config.json = widget.getAttribute("data-json");
|
config.json = widget.getAttribute("data-json");
|
||||||
config.animation = widget.getAttribute("data-animation");
|
config.animation = widget.getAttribute("data-animation");
|
||||||
if (widget.getAttribute("data-images-path")) config.imagesPath = widget.getAttribute("data-images-path");
|
if (widget.getAttribute("data-images-path")) config.imagesPath = widget.getAttribute("data-images-path");
|
||||||
|
if (widget.getAttribute("data-atlas-pages")) config.atlasPages = widget.getAttribute("data-atlas-pages").split(",");
|
||||||
if (widget.getAttribute("data-skin")) config.skin = widget.getAttribute("data-skin");
|
if (widget.getAttribute("data-skin")) config.skin = widget.getAttribute("data-skin");
|
||||||
if (widget.getAttribute("data-loop")) config.loop = widget.getAttribute("data-loop") === "true";
|
if (widget.getAttribute("data-loop")) config.loop = widget.getAttribute("data-loop") === "true";
|
||||||
if (widget.getAttribute("data-scale")) config.scale = parseFloat(widget.getAttribute("data-scale"));
|
if (widget.getAttribute("data-scale")) config.scale = parseFloat(widget.getAttribute("data-scale"));
|
||||||
@ -303,6 +310,7 @@ module spine {
|
|||||||
atlas: string;
|
atlas: string;
|
||||||
animation: string;
|
animation: string;
|
||||||
imagesPath: string;
|
imagesPath: string;
|
||||||
|
atlasPages: string[];
|
||||||
skin = "default";
|
skin = "default";
|
||||||
loop = true;
|
loop = true;
|
||||||
scale = 1.0;
|
scale = 1.0;
|
||||||
|
|||||||
@ -69,9 +69,8 @@ namespace Spine.Unity.Examples {
|
|||||||
SetXPosition(endX);
|
SetXPosition(endX);
|
||||||
separator.enabled = true; // Enable Separator when hit
|
separator.enabled = true; // Enable Separator when hit
|
||||||
var poleTrack = state.SetAnimation(0, pole, false);
|
var poleTrack = state.SetAnimation(0, pole, false);
|
||||||
float duration = poleTrack.TrackEnd;
|
yield return new WaitForSpineAnimationComplete(poleTrack);
|
||||||
poleTrack.TrackEnd = float.PositiveInfinity;
|
yield return new WaitForSeconds(1f);
|
||||||
yield return new WaitForSeconds(duration + 1f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1079,7 +1079,7 @@ namespace Spine.Unity.Editor {
|
|||||||
AssetDatabase.CreateAsset(skeletonDataAsset, filePath);
|
AssetDatabase.CreateAsset(skeletonDataAsset, filePath);
|
||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
} else {
|
} else {
|
||||||
skeletonDataAsset.Reset();
|
skeletonDataAsset.Clear();
|
||||||
skeletonDataAsset.GetSkeletonData(true);
|
skeletonDataAsset.GetSkeletonData(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1312,16 +1312,16 @@ namespace Spine.Unity.Editor {
|
|||||||
anim.skeletonDataAsset = skeletonDataAsset;
|
anim.skeletonDataAsset = skeletonDataAsset;
|
||||||
|
|
||||||
// Detect "Lit" shader and automatically enable calculateNormals.
|
// Detect "Lit" shader and automatically enable calculateNormals.
|
||||||
bool requiresNormals = false;
|
// bool requiresNormals = false;
|
||||||
foreach (AtlasAsset atlasAsset in anim.skeletonDataAsset.atlasAssets) {
|
// foreach (AtlasAsset atlasAsset in anim.skeletonDataAsset.atlasAssets) {
|
||||||
foreach (Material m in atlasAsset.materials) {
|
// foreach (Material m in atlasAsset.materials) {
|
||||||
if (m.shader.name.Contains("Lit")) {
|
// if (m.shader.name.Contains("Lit")) {
|
||||||
requiresNormals = true;
|
// requiresNormals = true;
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
anim.calculateNormals = requiresNormals;
|
// anim.calculateNormals = requiresNormals;
|
||||||
|
|
||||||
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
|
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
@ -1352,8 +1352,9 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
static void EnableTK2D () {
|
static void EnableTK2D () {
|
||||||
bool added = false;
|
bool added = false;
|
||||||
foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
|
foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
|
||||||
if (group == BuildTargetGroup.Unknown)
|
int gi = (int)group;
|
||||||
|
if (gi == 15 || gi == 16 || group == BuildTargetGroup.Unknown)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
|
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
|
||||||
@ -1379,6 +1380,10 @@ namespace Spine.Unity.Editor {
|
|||||||
static void DisableTK2D () {
|
static void DisableTK2D () {
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
|
foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
|
||||||
|
int gi = (int)group;
|
||||||
|
if (gi == 15 || gi == 16 || group == BuildTargetGroup.Unknown)
|
||||||
|
continue;
|
||||||
|
|
||||||
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
|
string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
|
||||||
if (defines.Contains(SPINE_TK2D_DEFINE)) {
|
if (defines.Contains(SPINE_TK2D_DEFINE)) {
|
||||||
removed = true;
|
removed = true;
|
||||||
|
|||||||
@ -62,14 +62,13 @@ namespace Spine.Unity {
|
|||||||
Debug.LogWarning("TrackEntry was null. Coroutine will continue immediately.");
|
Debug.LogWarning("TrackEntry was null. Coroutine will continue immediately.");
|
||||||
m_WasFired = true;
|
m_WasFired = true;
|
||||||
} else {
|
} else {
|
||||||
// Function normally.
|
|
||||||
trackEntry.Complete += HandleComplete;
|
trackEntry.Complete += HandleComplete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Reuse
|
#region Reuse
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// One optimization high-frequency YieldInstruction returns is to cache instances to minimize pressure.
|
/// One optimization high-frequency YieldInstruction returns is to cache instances to minimize GC pressure.
|
||||||
/// Use NowWaitFor to reuse the same instance of WaitForSpineAnimationComplete.</summary>
|
/// Use NowWaitFor to reuse the same instance of WaitForSpineAnimationComplete.</summary>
|
||||||
public WaitForSpineAnimationComplete NowWaitFor (Spine.TrackEntry trackEntry) {
|
public WaitForSpineAnimationComplete NowWaitFor (Spine.TrackEntry trackEntry) {
|
||||||
SafeSubscribe(trackEntry);
|
SafeSubscribe(trackEntry);
|
||||||
|
|||||||
@ -0,0 +1,94 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes Software License v2.5
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2016, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
||||||
|
* non-transferable license to use, install, execute, and perform the Spine
|
||||||
|
* Runtimes software and derivative works solely for personal or internal
|
||||||
|
* use. Without the written permission of Esoteric Software (see Section 2 of
|
||||||
|
* the Spine Software License Agreement), you may not (a) modify, translate,
|
||||||
|
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
||||||
|
* create derivative works or improvements of the Spine Runtimes or (b) remove,
|
||||||
|
* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
||||||
|
* or other intellectual property or proprietary rights notices on or in the
|
||||||
|
* Software, including any copy thereof. Redistributions in binary or source
|
||||||
|
* form must include this license and terms.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS) 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#if (UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
|
||||||
|
#define PREUNITY_5_3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Collections;
|
||||||
|
using Spine;
|
||||||
|
|
||||||
|
namespace Spine.Unity {
|
||||||
|
/// <summary>
|
||||||
|
/// Use this as a condition-blocking yield instruction for Unity Coroutines.
|
||||||
|
/// The routine will pause until the AnimationState.TrackEntry fires its End event.</summary>
|
||||||
|
public class WaitForSpineTrackEntryEnd : IEnumerator {
|
||||||
|
|
||||||
|
bool m_WasFired = false;
|
||||||
|
|
||||||
|
public WaitForSpineTrackEntryEnd (Spine.TrackEntry trackEntry) {
|
||||||
|
#if PREUNITY_5_3
|
||||||
|
Debug.LogWarning("Unity 5.3 or later is required for Spine Unity custom yield instructions to function correctly.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SafeSubscribe(trackEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleEnd (TrackEntry trackEntry) {
|
||||||
|
m_WasFired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SafeSubscribe (Spine.TrackEntry trackEntry) {
|
||||||
|
if (trackEntry == null) {
|
||||||
|
// Break immediately if trackEntry is null.
|
||||||
|
Debug.LogWarning("TrackEntry was null. Coroutine will continue immediately.");
|
||||||
|
m_WasFired = true;
|
||||||
|
} else {
|
||||||
|
trackEntry.End += HandleEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Reuse
|
||||||
|
/// <summary>
|
||||||
|
/// One optimization high-frequency YieldInstruction returns is to cache instances to minimize GC pressure.
|
||||||
|
/// Use NowWaitFor to reuse the same instance of WaitForSpineAnimationEnd.</summary>
|
||||||
|
public WaitForSpineTrackEntryEnd NowWaitFor (Spine.TrackEntry trackEntry) {
|
||||||
|
SafeSubscribe(trackEntry);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IEnumerator
|
||||||
|
bool IEnumerator.MoveNext () {
|
||||||
|
if (m_WasFired) {
|
||||||
|
((IEnumerator)this).Reset(); // auto-reset for YieldInstruction reuse
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void IEnumerator.Reset () { m_WasFired = false; }
|
||||||
|
object IEnumerator.Current { get { return null; } }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8036c6c2897d2764db92f632d2aef568
|
||||||
|
timeCreated: 1480672707
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -132,8 +132,8 @@ namespace Spine.Unity.Editor {
|
|||||||
skeleton.FlipY = EditorGUILayout.ToggleLeft("skeleton.FlipY", skeleton.FlipY);
|
skeleton.FlipY = EditorGUILayout.ToggleLeft("skeleton.FlipY", skeleton.FlipY);
|
||||||
requireRepaint |= EditorGUI.EndChangeCheck();
|
requireRepaint |= EditorGUI.EndChangeCheck();
|
||||||
|
|
||||||
foreach (var t in skeleton.IkConstraints)
|
// foreach (var t in skeleton.IkConstraints)
|
||||||
EditorGUILayout.LabelField(t.Data.Name + " " + t.Mix + " " + t.Target.Data.Name);
|
// EditorGUILayout.LabelField(t.Data.Name + " " + t.Mix + " " + t.Target.Data.Name);
|
||||||
|
|
||||||
showSlots.target = EditorGUILayout.Foldout(showSlots.target, SlotsRootLabel);
|
showSlots.target = EditorGUILayout.Foldout(showSlots.target, SlotsRootLabel);
|
||||||
if (showSlots.faded > 0) {
|
if (showSlots.faded > 0) {
|
||||||
|
|||||||
@ -110,12 +110,13 @@ namespace Spine.Unity {
|
|||||||
public Transform boneRoot;
|
public Transform boneRoot;
|
||||||
|
|
||||||
void Update () {
|
void Update () {
|
||||||
if (boneRoot != null && skeletonRenderer.skeleton != null) {
|
var skeleton = skeletonRenderer.skeleton;
|
||||||
|
if (boneRoot != null && skeleton != null) {
|
||||||
Vector3 flipScale = Vector3.one;
|
Vector3 flipScale = Vector3.one;
|
||||||
if (skeletonRenderer.skeleton.FlipX)
|
if (skeleton.FlipX)
|
||||||
flipScale.x = -1;
|
flipScale.x = -1;
|
||||||
|
|
||||||
if (skeletonRenderer.skeleton.FlipY)
|
if (skeleton.FlipY)
|
||||||
flipScale.y = -1;
|
flipScale.y = -1;
|
||||||
|
|
||||||
boneRoot.localScale = flipScale;
|
boneRoot.localScale = flipScale;
|
||||||
|
|||||||
@ -121,7 +121,7 @@ namespace Spine.Unity {
|
|||||||
cachedTransform.localPosition = new Vector3(bone.x, bone.y, 0);
|
cachedTransform.localPosition = new Vector3(bone.x, bone.y, 0);
|
||||||
|
|
||||||
if (rotation) {
|
if (rotation) {
|
||||||
if (!bone.data.transformMode.InheritsRotation()) {
|
if (bone.data.transformMode.InheritsRotation()) {
|
||||||
cachedTransform.localRotation = Quaternion.Euler(0, 0, bone.AppliedRotation);
|
cachedTransform.localRotation = Quaternion.Euler(0, 0, bone.AppliedRotation);
|
||||||
} else {
|
} else {
|
||||||
Vector3 euler = skeletonTransform.rotation.eulerAngles;
|
Vector3 euler = skeletonTransform.rotation.eulerAngles;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user