From 9b801a993ea8f998ae64db8e970a18a50f28da1b Mon Sep 17 00:00:00 2001 From: badlogic Date: Sat, 11 Jan 2020 15:35:56 +0100 Subject: [PATCH] [lua] Fixed animation layering. Cause of the bug was a few places using pairs instead of manually iterating through all indices from 0 to len. Closes #1574. --- spine-lua/AnimationState.lua | 126 +++++++++++++++++++++-------------- spine-lua/utils.lua | 3 + 2 files changed, 78 insertions(+), 51 deletions(-) diff --git a/spine-lua/AnimationState.lua b/spine-lua/AnimationState.lua index 4a2943c98..83483fa5e 100644 --- a/spine-lua/AnimationState.lua +++ b/spine-lua/AnimationState.lua @@ -227,7 +227,10 @@ function AnimationState:update (delta) delta = delta * self.timeScale local tracks = self.tracks local queue = self.queue - for i,current in pairs(tracks) do + local numTracks = #tracks + local i = 0 + while i <= numTracks do + current = tracks[i] if current then current.animationLast = current.nextAnimationLast current.trackLast = current.nextTrackLast @@ -290,6 +293,7 @@ function AnimationState:update (delta) end end end + i = i + 1 end queue:drain() @@ -329,51 +333,57 @@ function AnimationState:apply (skeleton) local queue = self.queue local applied = false - for i,current in pairs(tracks) do - if not (current == nil or current.delay > 0) then - applied = true + local numTracks = #tracks + local i = 0 + while i <= numTracks do + current = tracks[i] + if current then + if not (current == nil or current.delay > 0) then + applied = true - local blend = current.mixBlend - if i == 0 then blend = MixBlend.first end + local blend = current.mixBlend + if i == 0 then blend = MixBlend.first end - -- Apply mixing from entries first. - local mix = current.alpha - if current.mixingFrom then - mix = mix * self:applyMixingFrom(current, skeleton, blend) - elseif current.trackTime >= current.trackEnd and current.next == nil then - mix = 0 - end - - -- Apply current entry. - local animationLast = current.animationLast - local animationTime = current:getAnimationTime() - local timelines = current.animation.timelines - if (i == 0 and mix == 1) or blend == MixBlend.add then - for i,timeline in ipairs(timelines) do - timeline:apply(skeleton, animationLast, animationTime, self.events, mix, blend, MixDirection._in) + -- Apply mixing from entries first. + local mix = current.alpha + if current.mixingFrom then + mix = mix * self:applyMixingFrom(current, skeleton, blend) + elseif current.trackTime >= current.trackEnd and current.next == nil then + mix = 0 end - else - local timelineMode = current.timelineMode - local firstFrame = #current.timelinesRotation == 0 - local timelinesRotation = current.timelinesRotation - for ii,timeline in ipairs(timelines) do - local timelineBlend = MixBlend.setup - if clearBit(timelineMode[ii], NOT_LAST) == SUBSEQUENT then timelineBlend = blend end + -- Apply current entry. + local animationLast = current.animationLast + local animationTime = current:getAnimationTime() + local timelines = current.animation.timelines + if (i == 0 and mix == 1) or blend == MixBlend.add then + for i,timeline in ipairs(timelines) do + timeline:apply(skeleton, animationLast, animationTime, self.events, mix, blend, MixDirection._in) + end + else + local timelineMode = current.timelineMode + local firstFrame = #current.timelinesRotation == 0 + local timelinesRotation = current.timelinesRotation - if timeline.type == Animation.TimelineType.rotate then - self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii * 2, - firstFrame) - else - timeline:apply(skeleton, animationLast, animationTime, self.events, mix, timelineBlend, MixDirection._in) + for ii,timeline in ipairs(timelines) do + local timelineBlend = MixBlend.setup + if clearBit(timelineMode[ii], NOT_LAST) == SUBSEQUENT then timelineBlend = blend end + + if timeline.type == Animation.TimelineType.rotate then + self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii * 2, + firstFrame) + else + timeline:apply(skeleton, animationLast, animationTime, self.events, mix, timelineBlend, MixDirection._in) + end end end + self:queueEvents(current, animationTime) + self.events = {}; + current.nextAnimationLast = animationTime + current.nextTrackLast = current.trackTime end - self:queueEvents(current, animationTime) - self.events = {}; - current.nextAnimationLast = animationTime - current.nextTrackLast = current.trackTime end + i = i + 1 end queue:drain() @@ -602,7 +612,9 @@ function AnimationState:clearTracks () local tracks = self.tracks local oldDrainDisabled = queue.drainDisabled queue.drainDisabled = true; - for i,track in pairs(tracks) do + local numTracks = #tracks + local i = 0 + while i <= numTracks do self:clearTrack(i) end tracks = {} @@ -751,8 +763,13 @@ function AnimationState:setEmptyAnimations (mixDuration) local queue = self.queue local oldDrainDisabled = queue.drainDisabled queue.drainDisabled = true - for i,current in pairs(self.tracks) do + local tracks = self.tracks + local numTracks = #tracks + local i = 0 + while i <= numTracks do + current = tracks[i] if current then self:setEmptyAnimation(current.trackIndex, mixDuration) end + i = i + 1 end queue.drainDisabled = oldDrainDisabled queue:drain() @@ -814,21 +831,28 @@ function AnimationState:_animationsChanged () self.propertyIDs = {} local highestIndex = -1 - for i, entry in pairs(self.tracks) do - if i > highestIndex then highestIndex = i end + local tracks = self.tracks + local numTracks = #tracks + local i = 0 + while i <= numTracks do + current = tracks[i] + if current then + if i > highestIndex then highestIndex = i end - if entry then - while entry.mixingFrom do - entry = entry.mixingFrom - end - - repeat - if (entry.mixingTo == nil or entry.mixBlend ~= MixBlend.add) then - self:computeHold(entry) + if entry then + while entry.mixingFrom do + entry = entry.mixingFrom end - entry = entry.mixingTo - until (entry == nil) + + repeat + if (entry.mixingTo == nil or entry.mixBlend ~= MixBlend.add) then + self:computeHold(entry) + end + entry = entry.mixingTo + until (entry == nil) + end end + i = i + 1 end self.propertyIDs = {} diff --git a/spine-lua/utils.lua b/spine-lua/utils.lua index 842faae21..cf6a1cbc1 100644 --- a/spine-lua/utils.lua +++ b/spine-lua/utils.lua @@ -174,10 +174,12 @@ function utils.randomTriangularWith(min, max, mode) end function utils.testBit(value, bit) + if (value == nil) then return 0 end return value % (2 * bit) >= bit end function utils.setBit(value, bit) + if (value == nil) then return 0 end if value % (2 * bit) >= bit then return value end @@ -185,6 +187,7 @@ function utils.setBit(value, bit) end function utils.clearBit(value, bit) + if (value == nil) then return 0 end if value % (2 * bit) >= bit then return value - bit end