From dbd6ae87ad7844a69c48f843aac5931c4539015d Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Thu, 17 Oct 2013 16:06:18 +0200 Subject: [PATCH] Moved firing complete event to apply. Fixed missing keys on last frame when animation changes. --- .../src/spine/animation/AnimationState.as | 31 +++++---- spine-c/src/spine/AnimationState.c | 44 ++++++------ spine-js/spine.js | 65 +++++++++--------- .../spine/AnimationState.java | 31 +++++---- spine-lua/AnimationState.lua | 67 +++++++++---------- 5 files changed, 116 insertions(+), 122 deletions(-) diff --git a/spine-as3/spine-as3/src/spine/animation/AnimationState.as b/spine-as3/spine-as3/src/spine/animation/AnimationState.as index e333ea87c..e9b3abf79 100644 --- a/spine-as3/spine-as3/src/spine/animation/AnimationState.as +++ b/spine-as3/spine-as3/src/spine/animation/AnimationState.as @@ -54,26 +54,16 @@ public class AnimationState { var current:TrackEntry = _tracks[i]; if (!current) continue; - var trackDelta:Number = delta * current.timeScale; - var time:Number = current.time + trackDelta; - var endTime:Number = current.endTime; - - current.time = time; + var trackDelta:Number = delta * current.timeScale; + current.time += trackDelta; if (current.previous) { current.previous.time += trackDelta; current.mixTime += trackDelta; } - - // Check if completed the animation or a loop iteration. - if (current.loop ? (current.lastTime % endTime > time % endTime) : (current.lastTime < endTime && time >= endTime)) { - var count:int = (int)(time / endTime); - if (current.onComplete != null) current.onComplete(i, count); - if (onComplete != null) onComplete(i, count); - } - + var next:TrackEntry = current.next; if (next) { - if (time - trackDelta > next.delay) setCurrent(i, next); + if (current.lastTime >= 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); @@ -89,8 +79,10 @@ public class AnimationState { _events.length = 0; var time:Number = current.time; + var lastTime:Number = current.lastTime; + var endTime:Number = current.endTime; var loop:Boolean = current.loop; - if (!loop && time > current.endTime) time = current.endTime; + if (!loop && time > endTime) time = endTime; var previous:TrackEntry = current.previous; if (!previous) @@ -112,7 +104,14 @@ public class AnimationState { if (current.onEvent != null) current.onEvent(i, event); if (onEvent != null) onEvent(i, event); } - + + // Check if completed the animation or a loop iteration. + if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { + var count:int = (int)(time / endTime); + if (current.onComplete != null) current.onComplete(i, count); + if (onComplete != null) onComplete(i, count); + } + current.lastTime = current.time; } } diff --git a/spine-c/src/spine/AnimationState.c b/spine-c/src/spine/AnimationState.c index 71e350d3a..f3ee632ac 100644 --- a/spine-c/src/spine/AnimationState.c +++ b/spine-c/src/spine/AnimationState.c @@ -85,33 +85,21 @@ void spAnimationState_dispose (spAnimationState* self) { void spAnimationState_update (spAnimationState* self, float delta) { int i; - float time, endTime, trackDelta; + float trackDelta; delta *= self->timeScale; for (i = 0; i < self->trackCount; i++) { spTrackEntry* current = self->tracks[i]; if (!current) continue; trackDelta = delta * current->timeScale; - time = current->time + trackDelta; - endTime = current->endTime; - - current->time = time; + current->time += trackDelta; if (current->previous) { current->previous->time += trackDelta; current->mixTime += trackDelta; } - /* Check if completed the animation or a loop iteration. */ - if (current->loop ? - (FMOD(current->lastTime, endTime) > FMOD(time, endTime)) : (current->lastTime < endTime && time >= endTime)) { - int count = (int)(time / endTime); - if (current->listener) current->listener(self, i, ANIMATION_COMPLETE, 0, count); - if (self->listener) self->listener(self, i, ANIMATION_COMPLETE, 0, count); - if (i >= self->trackCount || self->tracks[i] != current) continue; - } - if (current->next) { - if (time - trackDelta >= current->next->delay) _spAnimationState_setCurrent(self, i, current->next); + if (current->lastTime >= current->next->delay) _spAnimationState_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) spAnimationState_clearTrack(self, i); @@ -137,8 +125,7 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { previous = current->previous; if (!previous) { - spAnimation_apply(current->animation, skeleton, current->lastTime, time, current->loop, internal->events, - &eventCount); + spAnimation_apply(current->animation, skeleton, current->lastTime, time, current->loop, internal->events, &eventCount); } else { float alpha = current->mixTime / current->mixDuration; @@ -151,8 +138,8 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { _spTrackEntry_dispose(current->previous); current->previous = 0; } - spAnimation_mix(current->animation, skeleton, current->lastTime, time, current->loop, internal->events, - &eventCount, alpha); + spAnimation_mix(current->animation, skeleton, current->lastTime, time, current->loop, internal->events, &eventCount, + alpha); } for (ii = 0; ii < eventCount; ii++) { @@ -161,6 +148,15 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { if (self->listener) self->listener(self, i, ANIMATION_EVENT, event, 0); } + /* Check if completed the animation or a loop iteration. */ + if (current->loop ? (FMOD(current->lastTime, current->endTime) > FMOD(time, current->endTime)) // + : (current->lastTime < current->endTime && time >= current->endTime)) { + int count = (int)(time / current->endTime); + if (current->listener) current->listener(self, i, ANIMATION_COMPLETE, 0, count); + if (self->listener) self->listener(self, i, ANIMATION_COMPLETE, 0, count); + if (i >= self->trackCount || self->tracks[i] != current) continue; + } + if (i >= self->trackCount || self->tracks[i] != current) continue; current->lastTime = current->time; } @@ -222,7 +218,8 @@ void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEnt if (self->listener) self->listener(self, index, ANIMATION_START, 0, 0); } -spTrackEntry* spAnimationState_setAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, int/*bool*/loop) { +spTrackEntry* spAnimationState_setAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, + int/*bool*/loop) { spAnimation* animation = spSkeletonData_findAnimation(self->data->skeletonData, animationName); return spAnimationState_setAnimation(self, trackIndex, animation, loop); } @@ -241,13 +238,14 @@ spTrackEntry* spAnimationState_setAnimation (spAnimationState* self, int trackIn return entry; } -spTrackEntry* spAnimationState_addAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, int/*bool*/loop, - float delay) { +spTrackEntry* spAnimationState_addAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, + int/*bool*/loop, float delay) { spAnimation* animation = spSkeletonData_findAnimation(self->data->skeletonData, animationName); return spAnimationState_addAnimation(self, trackIndex, animation, loop, delay); } -spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop, float delay) { +spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop, + float delay) { spTrackEntry* last; spTrackEntry* entry = _spTrackEntry_create(); diff --git a/spine-js/spine.js b/spine-js/spine.js index 2d00195e5..22b48a536 100644 --- a/spine-js/spine.js +++ b/spine-js/spine.js @@ -142,7 +142,7 @@ spine.Slot.prototype = { this.g = data.g; this.b = data.b; this.a = data.a; - + var slotDatas = this.skeleton.data.slots; for (var i = 0, n = slotDatas.length; i < n; i++) { if (slotDatas[i] == data) { @@ -969,27 +969,17 @@ spine.AnimationState.prototype = { for (var i = 0; i < this.tracks.length; i++) { var current = this.tracks[i]; if (!current) continue; - + var trackDelta = delta * current.timeScale; - var time = current.time + trackDelta; - var endTime = current.endTime; - - current.time = time; + current.time += trackDelta; if (current.previous) { current.previous.time += trackDelta; current.mixTime += trackDelta; } - - // Check if completed the animation or a loop iteration. - if (current.loop ? (current.lastTime % endTime > time % endTime) : (current.lastTime < endTime && time >= endTime)) { - var count = Math.floor(time / endTime); - if (current.onComplete) current.onComplete(i, count); - if (this.onComplete) this.onComplete(i, count); - } - + var next = current.next; if (next) { - if (time - trackDelta > next.delay) this.setCurrent(i, next); + if (current.lastTime >= next.delay) this.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) this.clearTrack(i); @@ -1000,13 +990,15 @@ spine.AnimationState.prototype = { for (var i = 0; i < this.tracks.length; i++) { var current = this.tracks[i]; if (!current) continue; - + this.events.length = 0; - + var time = current.time; + var lastTime = current.lastTime; + var endTime = current.endTime; var loop = current.loop; - if (!loop && time > current.endTime) time = current.endTime; - + if (!loop && time > endTime) time = endTime; + var previous = current.previous; if (!previous) current.animation.apply(skeleton, current.lastTime, time, loop, this.events); @@ -1014,7 +1006,7 @@ spine.AnimationState.prototype = { var previousTime = previous.time; if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); - + var alpha = current.mixTime / current.mixDuration; if (alpha >= 1) { alpha = 1; @@ -1022,17 +1014,24 @@ spine.AnimationState.prototype = { } current.animation.mix(skeleton, current.lastTime, time, loop, this.events, alpha); } - + for (var ii = 0, nn = this.events.length; ii < nn; ii++) { var event = this.events[ii]; if (current.onEvent != null) current.onEvent(i, event); if (this.onEvent != null) this.onEvent(i, event); } - + + // Check if completed the animation or a loop iteration. + if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { + var count = Math.floor(time / endTime); + if (current.onComplete) current.onComplete(i, count); + if (this.onComplete) this.onComplete(i, count); + } + current.lastTime = current.time; } }, - clearTracks: function () { + clearTracks: function () { for (var i = 0, n = this.tracks.length; i < n; i++) this.clearTrack(i); this.tracks.length = 0; @@ -1057,19 +1056,19 @@ spine.AnimationState.prototype = { var current = this._expandToIndex(index); if (current) { current.previous = null; - + if (current.onEnd != null) current.onEnd(index); if (this.onEnd != null) this.onEnd(index); - + entry.mixDuration = this.data.getMix(current.animation, entry.animation); if (entry.mixDuration > 0) { entry.mixTime = 0; entry.previous = current; } } - + this.tracks[index] = entry; - + if (entry.onStart != null) entry.onStart(index); if (this.onStart != null) this.onStart(index); }, @@ -1099,7 +1098,7 @@ spine.AnimationState.prototype = { entry.animation = animation; entry.loop = loop; entry.endTime = animation.duration; - + var last = this._expandToIndex(trackIndex); if (last) { while (last.next) @@ -1107,7 +1106,7 @@ spine.AnimationState.prototype = { last.next = entry; } else this.tracks[trackIndex] = entry; - + if (delay <= 0) { if (last) { if (last.time < last.endTime) delay += last.endTime - last.time; @@ -1116,9 +1115,9 @@ spine.AnimationState.prototype = { delay = 0; } entry.delay = delay; - + return entry; - }, + }, /** May be null. */ getCurrent: function (trackIndex) { if (trackIndex >= this.tracks.length) return null; @@ -1669,7 +1668,7 @@ spine.SkeletonBounds.prototype = { var boundingBoxes = this.boundingBoxes; var polygonPool = this.polygonPool; var polygons = this.polygons; - + boundingBoxes.length = 0; for (var i = 0, n = polygons.length; i < n; i++) polygonPool.push(polygons[i]); @@ -1756,7 +1755,7 @@ spine.SkeletonBounds.prototype = { }, /** Returns true if the polygon contains the point. */ polygonContainsPoint: function (polygon, x, y) { - var nn = polygon.length; + var nn = polygon.length; var prevIndex = nn - 2; var inside = false; for (var ii = 0; ii < nn; ii += 2) { diff --git a/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java b/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java index 79a921485..5b30c813a 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java @@ -57,26 +57,15 @@ public class AnimationState { if (current == null) continue; float trackDelta = delta * current.timeScale; - float time = current.time + trackDelta; - float endTime = current.endTime; - - current.time = time; + current.time += trackDelta; if (current.previous != null) { current.previous.time += trackDelta; current.mixTime += trackDelta; } - // Check if completed the animation or a loop iteration. - if (current.loop ? (current.lastTime % endTime > time % endTime) : (current.lastTime < endTime && time >= endTime)) { - int count = (int)(time / endTime); - if (current.listener != null) current.listener.complete(i, count); - for (int ii = 0, nn = listeners.size; ii < nn; ii++) - listeners.get(ii).complete(i, count); - } - TrackEntry next = current.next; if (next != null) { - if (time - trackDelta > next.delay) setCurrent(i, next); + if (current.lastTime >= 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); @@ -95,12 +84,14 @@ public class AnimationState { events.size = 0; float time = current.time; + float lastTime = current.lastTime; + float endTime = current.endTime; boolean loop = current.loop; - if (!loop && time > current.endTime) time = current.endTime; + if (!loop && time > endTime) time = endTime; TrackEntry previous = current.previous; if (previous == null) - current.animation.apply(skeleton, current.lastTime, time, loop, events); + current.animation.apply(skeleton, lastTime, time, loop, events); else { float previousTime = previous.time; if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; @@ -112,7 +103,7 @@ public class AnimationState { Pools.free(previous); current.previous = null; } - current.animation.mix(skeleton, current.lastTime, time, loop, events, alpha); + current.animation.mix(skeleton, lastTime, time, loop, events, alpha); } for (int ii = 0, nn = events.size; ii < nn; ii++) { @@ -122,6 +113,14 @@ public class AnimationState { listeners.get(iii).event(i, event); } + // Check if completed the animation or a loop iteration. + if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { + int count = (int)(time / endTime); + if (current.listener != null) current.listener.complete(i, count); + for (int ii = 0, nn = listeners.size; ii < nn; ii++) + listeners.get(ii).complete(i, count); + } + current.lastTime = current.time; } } diff --git a/spine-lua/AnimationState.lua b/spine-lua/AnimationState.lua index 61613c2d1..f90ae2c8f 100644 --- a/spine-lua/AnimationState.lua +++ b/spine-lua/AnimationState.lua @@ -48,10 +48,10 @@ function AnimationState.new (data) local current = self.tracks[index] if current then current.previous = nil - + if current.onEnd then current.onEnd(index) end if self.onEnd then self.onEnd(index) end - + entry.mixDuration = self.data:getMix(current.animation.name, entry.animation.name) if entry.mixDuration > 0 then entry.mixTime = 0 @@ -70,31 +70,15 @@ function AnimationState.new (data) for i,current in pairs(self.tracks) do if current then local trackDelta = delta * current.timeScale - local time = current.time + trackDelta - local endTime = current.endTime - - current.time = time + current.time = current.time + trackDelta if current.previous then current.previous.time = current.previous.time + trackDelta current.mixTime = current.mixTime + trackDelta end - - -- Check if completed the animation or a loop iteration. - local complete - if current.loop then - complete = current.lastTime % endTime > time % endTime - else - complete = current.lastTime < endTime and time >= endTime - end - if complete then - local count = math.floor(time / endTime) - if current.onComplete then current.onComplete(i, count) end - if self.onComplete then self.onComplete(i, count) end - end - + local next = current.next if next then - if time - trackDelta > next.delay then setCurrent(i, next) end + if current.lastTime >= next.delay then setCurrent(i, next) end else -- End non-looping animation when it reaches its end time and there is no next entry. if not current.loop and current.lastTime >= current.endTime then self:clearTrack(i) end @@ -102,14 +86,16 @@ function AnimationState.new (data) end end end - + function self:apply(skeleton) for i,current in pairs(self.tracks) do - if current then + if current then local time = current.time + local lastTime = current.lastTime + local endTime = current.endTime local loop = current.loop - if not loop and time > current.endTime then time = current.endTime end - + if not loop and time > endTime then time = endTime end + local previous = current.previous if not previous then current.animation:apply(skeleton, current.lastTime, time, loop, self.events) @@ -117,7 +103,7 @@ function AnimationState.new (data) local previousTime = previous.time if not previous.loop and previousTime > previous.endTime then previousTime = previous.endTime end previous.animation:apply(skeleton, previousTime, previousTime, previous.loop, nil) - + local alpha = current.mixTime / current.mixDuration if alpha >= 1 then alpha = 1 @@ -125,7 +111,7 @@ function AnimationState.new (data) end current.animation:mix(skeleton, current.lastTime, time, loop, self.events, alpha) end - + local eventCount = #self.events for ii = 1, eventCount, 1 do local event = self.events[ii] @@ -136,18 +122,31 @@ function AnimationState.new (data) table.remove(self.events) end + -- Check if completed the animation or a loop iteration. + local complete + if current.loop then + complete = lastTime % endTime > time % endTime + else + complete = lastTime < endTime and time >= endTime + end + if complete then + local count = math.floor(time / endTime) + if current.onComplete then current.onComplete(i, count) end + if self.onComplete then self.onComplete(i, count) end + end + current.lastTime = current.time end end end - + function self:clearTracks () for i,current in pairs(self.tracks) do self.clearTrack(i) end self.tracks = {} end - + function self:clearTrack (trackIndex) local current = self.tracks[trackIndex] if not current then return end @@ -157,7 +156,7 @@ function AnimationState.new (data) self.tracks[trackIndex] = nil end - + function self:setAnimationByName (trackIndex, animationName, loop) local animation = self.data.skeletonData:findAnimation(animationName) if not animation then error("Animation not found: " + animationName) end @@ -173,7 +172,7 @@ function AnimationState.new (data) setCurrent(trackIndex, entry) return entry end - + function self:addAnimationByName (trackIndex, animationName, loop, delay) local animation = self.data.skeletonData:findAnimation(animationName) if not animation then error("Animation not found: " + animationName) end @@ -187,7 +186,7 @@ function AnimationState.new (data) entry.animation = animation entry.loop = loop entry.endTime = animation.duration - + local last = self.tracks[trackIndex] if last then while (last.next) do @@ -197,7 +196,7 @@ function AnimationState.new (data) else self.tracks[trackIndex] = entry end - + delay = delay or 0 if delay <= 0 then if last then @@ -208,7 +207,7 @@ function AnimationState.new (data) end end entry.delay = delay - + return entry end