diff --git a/spine-c/include/spine/AnimationState.h b/spine-c/include/spine/AnimationState.h index bf07efe20..03e41a364 100644 --- a/spine-c/include/spine/AnimationState.h +++ b/spine-c/include/spine/AnimationState.h @@ -85,8 +85,7 @@ TrackEntry* AnimationState_setAnimationByName (AnimationState* self, int trackIn TrackEntry* AnimationState_setAnimation (AnimationState* self, int trackIndex, Animation* animation, int/*bool*/loop); /** Adds an animation to be played delay seconds after the current or last queued animation, taking into account any mix - * duration. - * @param animation May be 0 to queue clearing the AnimationState. */ + * duration. */ TrackEntry* AnimationState_addAnimationByName (AnimationState* self, int trackIndex, const char* animationName, int/*bool*/loop, float delay); TrackEntry* AnimationState_addAnimation (AnimationState* self, int trackIndex, Animation* animation, int/*bool*/loop, diff --git a/spine-c/src/spine/AnimationState.c b/spine-c/src/spine/AnimationState.c index 3ea4c0574..7be03b52b 100644 --- a/spine-c/src/spine/AnimationState.c +++ b/spine-c/src/spine/AnimationState.c @@ -39,7 +39,6 @@ #include #include #include -#include TrackEntry* _TrackEntry_create () { TrackEntry* entry = NEW(TrackEntry); @@ -110,11 +109,11 @@ void AnimationState_update (AnimationState* self, float delta) { if (self->listener) self->listener(self, i, ANIMATION_COMPLETE, 0, count); } - if (current->next && time >= current->next->delay) { - if (current->next->animation) - _AnimationState_setCurrent(self, i, current->next); - else - AnimationState_clearTrack(self, i); + if (current->next) { + if (time >= current->next->delay) _AnimationState_setCurrent(self, i, current->next); + } else { + /* End non-looping animation when it reaches its end time and there is no next entry. */ + if (!current->loop && current->lastTime >= current->endTime) AnimationState_clearTrack(self, i); } } } @@ -124,6 +123,7 @@ void AnimationState_apply (AnimationState* self, Skeleton* skeleton) { int i, ii; int eventCount; + float time; TrackEntry* previous; for (i = 0; i < self->trackCount; i++) { TrackEntry* current = self->tracks[i]; @@ -131,19 +131,26 @@ void AnimationState_apply (AnimationState* self, Skeleton* skeleton) { eventCount = 0; + time = current->time; + if (!current->loop && time > current->endTime) time = current->endTime; + previous = current->previous; if (!previous) { - Animation_apply(current->animation, skeleton, current->lastTime, current->time, current->loop, internal->events, + Animation_apply(current->animation, skeleton, current->lastTime, time, current->loop, internal->events, &eventCount); } else { float alpha = current->mixTime / current->mixDuration; - Animation_apply(previous->animation, skeleton, (float)INT_MAX, previous->time, previous->loop, 0, 0); + + float previousTime = previous->time; + if (!previous->loop && previousTime > previous->endTime) previousTime = previous->endTime; + Animation_apply(previous->animation, skeleton, previousTime, previousTime, previous->loop, 0, 0); + if (alpha >= 1) { alpha = 1; _TrackEntry_dispose(current->previous); current->previous = 0; } - Animation_mix(current->animation, skeleton, current->lastTime, current->time, current->loop, internal->events, + Animation_mix(current->animation, skeleton, current->lastTime, time, current->loop, internal->events, &eventCount, alpha); } diff --git a/spine-csharp/src/AnimationState.cs b/spine-csharp/src/AnimationState.cs index fcca14cba..d9c8c0a77 100644 --- a/spine-csharp/src/AnimationState.cs +++ b/spine-csharp/src/AnimationState.cs @@ -79,11 +79,11 @@ namespace Spine { } TrackEntry next = current.next; - if (next != null && time >= next.delay) { - if (next.animation != null) - SetCurrent(i, next); - else - Clear(i); + if (next != null) { + if (time >= next.delay) SetCurrent(i, next); + } else { + // End non-looping animation when it reaches its end time and there is no next entry. + if (!current.loop && current.lastTime >= current.endTime) ClearTrack(i); } } } @@ -97,17 +97,24 @@ namespace Spine { events.Clear(); + float time = current.time; + bool loop = current.loop; + if (!loop && time > current.endTime) time = current.endTime; + TrackEntry previous = current.previous; if (previous == null) - current.animation.Apply(skeleton, current.lastTime, current.time, current.loop, events); + current.animation.Apply(skeleton, current.lastTime, time, loop, events); else { - previous.animation.Apply(skeleton, int.MaxValue, previous.time, previous.loop, null); + float previousTime = previous.time; + if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; + previous.animation.Apply(skeleton, previousTime, previousTime, previous.loop, null); + float alpha = current.mixTime / current.mixDuration; if (alpha >= 1) { alpha = 1; current.previous = null; } - current.animation.Mix(skeleton, current.lastTime, current.time, current.loop, events, alpha); + current.animation.Mix(skeleton, current.lastTime, time, loop, events, alpha); } for (int ii = 0, nn = events.Count; ii < nn; ii++) { @@ -120,13 +127,13 @@ namespace Spine { } } - public void Clear () { + public void ClearTracks () { for (int i = 0, n = tracks.Count; i < n; i++) - Clear(i); + ClearTrack(i); tracks.Clear(); } - public void Clear (int trackIndex) { + public void ClearTrack (int trackIndex) { if (trackIndex >= tracks.Count) return; TrackEntry current = tracks[trackIndex]; if (current == null) return; @@ -195,7 +202,7 @@ namespace Spine { entry.animation = animation; entry.loop = loop; entry.time = 0; - entry.endTime = animation != null ? animation.Duration : 0; + entry.endTime = animation.Duration; TrackEntry last = ExpandToIndex(trackIndex); if (last != null) { @@ -206,10 +213,9 @@ namespace Spine { tracks[trackIndex] = entry; if (delay <= 0) { - if (last != null) { - delay += last.endTime; - if (animation != null) delay -= data.GetMix(last.animation, animation); - } else + if (last != null) + delay += last.endTime - data.GetMix(last.animation, animation); + else delay = 0; } entry.delay = delay; diff --git a/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java b/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java index cbbbcdc96..6c42d52cd 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java @@ -43,7 +43,7 @@ public class AnimationState { private Array tracks = new Array(); private final Array events = new Array(); private final Array listeners = new Array(); - private float timeScale; + private float timeScale = 1; public AnimationState (AnimationStateData data) { if (data == null) throw new IllegalArgumentException("data cannot be null."); @@ -75,11 +75,11 @@ public class AnimationState { } TrackEntry next = current.next; - if (next != null && time >= next.delay) { - if (next.animation != null) - setCurrent(i, next); - else - clear(i); + if (next != null) { + if (time >= next.delay) setCurrent(i, next); + } else { + // End non-looping animation when it reaches its end time and there is no next entry. + if (!current.loop && current.lastTime >= current.endTime) clearTrack(i); } } } @@ -94,18 +94,25 @@ public class AnimationState { events.size = 0; + float time = current.time; + boolean loop = current.loop; + if (!loop && time > current.endTime) time = current.endTime; + TrackEntry previous = current.previous; if (previous == null) - current.animation.apply(skeleton, current.lastTime, current.time, current.loop, events); + current.animation.apply(skeleton, current.lastTime, time, loop, events); else { - previous.animation.apply(skeleton, Integer.MAX_VALUE, previous.time, previous.loop, null); + float previousTime = previous.time; + if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; + previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); + float alpha = current.mixTime / current.mixDuration; if (alpha >= 1) { alpha = 1; Pools.free(previous); current.previous = null; } - current.animation.mix(skeleton, current.lastTime, current.time, current.loop, events, alpha); + current.animation.mix(skeleton, current.lastTime, time, loop, events, alpha); } for (int ii = 0, nn = events.size; ii < nn; ii++) { @@ -119,13 +126,13 @@ public class AnimationState { } } - public void clear () { + public void clearTracks () { for (int i = 0, n = tracks.size; i < n; i++) - clear(i); + clearTrack(i); tracks.clear(); } - public void clear (int trackIndex) { + public void clearTrack (int trackIndex) { if (trackIndex >= tracks.size) return; TrackEntry current = tracks.get(trackIndex); if (current == null) return; @@ -210,14 +217,13 @@ public class AnimationState { } /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param animation May be null to queue clearing the AnimationState. * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ public TrackEntry addAnimation (int trackIndex, Animation animation, boolean loop, float delay) { TrackEntry entry = Pools.obtain(TrackEntry.class); entry.animation = animation; entry.loop = loop; entry.time = 0; - entry.endTime = animation != null ? animation.getDuration() : 0; + entry.endTime = animation.getDuration(); TrackEntry last = expandToIndex(trackIndex); if (last != null) { @@ -228,10 +234,9 @@ public class AnimationState { tracks.set(trackIndex, entry); if (delay <= 0) { - if (last != null) { - delay += last.endTime; - if (animation != null) delay -= data.getMix(last.animation, animation); - } else + if (last != null) + delay += last.endTime - data.getMix(last.animation, animation); + else delay = 0; } entry.delay = delay;