mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 22:34:53 +08:00
[lua] Ported half of AnimationState
This commit is contained in:
parent
10e85c02e0
commit
44f5540d37
@ -228,6 +228,7 @@ function Animation.RotateTimeline.new (frameCount)
|
||||
local self = Animation.CurveTimeline.new(frameCount)
|
||||
self.boneIndex = -1
|
||||
self.frames = utils.newNumberArrayZero(frameCount * 2)
|
||||
self.type = TimelineType.rotate
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.rotate * SHL_24 + self.boneIndex
|
||||
@ -291,6 +292,7 @@ function Animation.TranslateTimeline.new (frameCount)
|
||||
local self = Animation.CurveTimeline.new(frameCount)
|
||||
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
|
||||
self.boneIndex = -1
|
||||
self.type = TimelineType.translate
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.translate * SHL_24 + self.boneIndex
|
||||
@ -349,6 +351,7 @@ function Animation.ScaleTimeline.new (frameCount)
|
||||
local Y = 2
|
||||
|
||||
local self = Animation.TranslateTimeline.new(frameCount)
|
||||
self.type = TimelineType.scale
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.scale * SHL_24 + self.boneIndex
|
||||
@ -417,6 +420,7 @@ function Animation.ShearTimeline.new (frameCount)
|
||||
local Y = 2
|
||||
|
||||
local self = Animation.TranslateTimeline.new(frameCount)
|
||||
self.type = TimelineType.shear
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.shear * SHL_24 + self.boneIndex
|
||||
@ -474,6 +478,7 @@ function Animation.ColorTimeline.new (frameCount)
|
||||
local self = Animation.CurveTimeline.new(frameCount)
|
||||
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
|
||||
self.slotIndex = -1
|
||||
self.type = TimelineType.color
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.color * SHL_24 + self.slotIndex
|
||||
@ -533,7 +538,8 @@ function Animation.AttachmentTimeline.new (frameCount)
|
||||
local self = {
|
||||
frames = utils.newNumberArrayZero(frameCount), -- time, ...
|
||||
attachmentNames = {},
|
||||
slotIndex = -1
|
||||
slotIndex = -1,
|
||||
type = TimelineType.attachment
|
||||
}
|
||||
|
||||
function self:getFrameCount ()
|
||||
@ -591,6 +597,7 @@ function Animation.DeformTimeline.new (frameCount)
|
||||
self.frameVertices = utils.newNumberArrayZero(frameCount)
|
||||
self.slotIndex = -1
|
||||
self.attachment = nil
|
||||
self.type = TimelineType.deform
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.deform * SHL_24 + self.slotIndex
|
||||
@ -711,7 +718,8 @@ Animation.EventTimeline = {}
|
||||
function Animation.EventTimeline.new (frameCount)
|
||||
local self = {
|
||||
frames = utils.newNumberArrayZero(frameCount),
|
||||
events = {}
|
||||
events = {},
|
||||
type = TimelineType.event
|
||||
}
|
||||
|
||||
function self:getPropertyId ()
|
||||
@ -767,7 +775,8 @@ Animation.DrawOrderTimeline = {}
|
||||
function Animation.DrawOrderTimeline.new (frameCount)
|
||||
local self = {
|
||||
frames = utils.newNumberArrayZero(frameCount),
|
||||
drawOrders = {}
|
||||
drawOrders = {},
|
||||
type = TimelineType.drawOrder
|
||||
}
|
||||
|
||||
function self:getPropertyId ()
|
||||
@ -830,6 +839,7 @@ function Animation.IkConstraintTimeline.new (frameCount)
|
||||
local self = Animation.CurveTimeline.new(frameCount)
|
||||
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, ...
|
||||
self.ikConstraintIndex = -1
|
||||
self.type = TimelineType.ikConstraint
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.ikConstraint * SHL_24 + self.ikConstraintIndex
|
||||
@ -903,6 +913,7 @@ function Animation.TransformConstraintTimeline.new (frameCount)
|
||||
local self = Animation.CurveTimeline.new(frameCount)
|
||||
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
|
||||
self.transformConstraintIndex = -1
|
||||
self.type = TimelineType.transformConstraint
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.transformConstraint * SHL_24 + self.transformConstraintIndex
|
||||
@ -977,6 +988,7 @@ function Animation.PathConstraintPositionTimeline.new (frameCount)
|
||||
local self = Animation.CurveTimeline.new(frameCount)
|
||||
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
|
||||
self.pathConstraintIndex = -1
|
||||
self.type = TimelineType.pathConstraintPosition
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.pathConstraintPosition * SHL_24 + self.pathConstraintIndex
|
||||
@ -1028,6 +1040,7 @@ function Animation.PathConstraintSpacingTimeline.new (frameCount)
|
||||
local self = Animation.CurveTimeline.new(frameCount)
|
||||
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
|
||||
self.pathConstraintIndex = -1
|
||||
self.type = TimelineType.pathConstraintSpacing
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.pathConstraintSpacing * SHL_24 + self.pathConstraintIndex
|
||||
@ -1082,6 +1095,7 @@ function Animation.PathConstraintMixTimeline.new (frameCount)
|
||||
local self = Animation.CurveTimeline.new(frameCount)
|
||||
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES)
|
||||
self.pathConstraintIndex = -1
|
||||
self.type = TimelineType.pathConstraintMix
|
||||
|
||||
function self:getPropertyId ()
|
||||
return TimelineType.pathConstraintMix * SHL_24 + self.pathConstraintIndex
|
||||
|
||||
@ -33,6 +33,9 @@ local table_insert = table.insert
|
||||
local utils = require "spine-lua.utils"
|
||||
local Animation = require "spine-lua.Animation"
|
||||
local AnimationStateData = require "spine-lua.AnimationStateData"
|
||||
local math_min = math.min
|
||||
local math_abs = math.abs
|
||||
local math_signum = utils.signum
|
||||
|
||||
local EventType = {
|
||||
start = 0,
|
||||
@ -142,6 +145,36 @@ function EventQueue:clear ()
|
||||
end
|
||||
|
||||
|
||||
local TrackEntry = {}
|
||||
TrackEntry.__index = TrackEntry
|
||||
|
||||
function TrackEntry.new ()
|
||||
local self = {
|
||||
animation = nil,
|
||||
next = nil, mixingFrom = nil,
|
||||
onStart = nil, onInterrupt = nil, onEnd = nil, onDispose = nil, onComplete = nil, onEvent = nil,
|
||||
trackIndex = 0,
|
||||
loop = false,
|
||||
eventThreshold = 0, attachmentThreshold = 0, drawOrderThreshold = 0,
|
||||
animationStart = 0, animationEnd = 0, animationLast = 0, nextAnimationLast = 0,
|
||||
delay = 0, trackTime = 0, trackLast = 0, nextTrackLast = 0, trackEnd = 0, timeScale = 0,
|
||||
alpha = 0, mixTime = 0, mixDuration = 0, mixAlpha = 0,
|
||||
timelinesFirst = {},
|
||||
timelinesRotation = {}
|
||||
}
|
||||
setmetatable(self, TrackEntry)
|
||||
return self
|
||||
end
|
||||
|
||||
function TrackEntry:getAnimationTime ()
|
||||
if loop then
|
||||
local duration = animationEnd - animationStart
|
||||
if duration == 0 then return animationStart end
|
||||
return (trackTime % duration) + animationStart
|
||||
end
|
||||
return math_min(trackTime + animationStart, animationEnd)
|
||||
end
|
||||
|
||||
local AnimationState = {}
|
||||
AnimationState.__index = AnimationState
|
||||
|
||||
@ -163,4 +196,181 @@ function AnimationState.new (data)
|
||||
return self
|
||||
end
|
||||
|
||||
AnimationState.TrackEntry = TrackEntry
|
||||
|
||||
function AnimationState:update (delta)
|
||||
delta = delta * self.timeScale
|
||||
local tracks = self.tracks
|
||||
local queue = self.queue
|
||||
for i,current in pairs(tracks) do
|
||||
if current then
|
||||
current.animationLast = current.nextAnimationLast
|
||||
current.trackLast = current.nextTrackLast
|
||||
|
||||
local currentDelta = delta * current.timeScale
|
||||
|
||||
local skip = false
|
||||
if current.delay > 0 then
|
||||
current.delay = current.delay - currentDelta
|
||||
if current.delay <= 0 then
|
||||
skip = true
|
||||
currentDelta = -current.delay
|
||||
current.delay = 0
|
||||
end
|
||||
end
|
||||
|
||||
if not skip then
|
||||
local next = current.next
|
||||
if next then
|
||||
-- When the next entry's delay is passed, change to the next entry, preserving leftover time.
|
||||
local nextTime = current.trackLast - next.delay
|
||||
if nextTime >= 0 then
|
||||
next.delay = 0
|
||||
next.trackTime = nextTime + delta * next.timeScale
|
||||
current.trackTime = current.trackTime + currentDelta
|
||||
self:setCurrent(i, next)
|
||||
while next.mixingFrom do
|
||||
next.mixTime = next.mixTime + currentDelta
|
||||
next = next.mixingFrom
|
||||
end
|
||||
skip = true
|
||||
end
|
||||
if not skip then
|
||||
self:updateMixingFrom(current, delta, true);
|
||||
end
|
||||
else
|
||||
self:updateMixingFrom(current, delta, true)
|
||||
-- Clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom.
|
||||
if current.trackLast >= current.trackEnd and current.mixingFrom == nil then
|
||||
tracks[i] = nil
|
||||
queue:_end(current)
|
||||
self:disposeNext(current)
|
||||
skip = true
|
||||
end
|
||||
end
|
||||
|
||||
if not skip then current.trackTime = current.trackTime + currentDelta end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
queue:drain()
|
||||
end
|
||||
|
||||
function AnimationState:updateMixingFrom (entry, delta, canEnd)
|
||||
local from = entry.mixingFrom
|
||||
if from == nil then return end
|
||||
|
||||
local queue = self.queue
|
||||
if canEnd and entry.mixTime >= entry.mixDuration and entry.mixTime > 0 then
|
||||
queue:_end(from)
|
||||
local newFrom = from.mixingFrom
|
||||
entry.mixingFrom = newFrom
|
||||
if newFrom == nil then return end
|
||||
entry.mixTime = from.mixTime;
|
||||
entry.mixDuration = from.mixDuration;
|
||||
from = newFrom;
|
||||
end
|
||||
|
||||
from.animationLast = from.nextAnimationLast
|
||||
from.trackLast = from.nextTrackLast
|
||||
local mixingFromDelta = delta * from.timeScale
|
||||
from.trackTime = from.trackTime + mixingFromDelta;
|
||||
entry.mixTime = entry.mixtime + mixingFromDelta;
|
||||
|
||||
self:updateMixingFrom(from, delta, canEnd and from.alpha == 1)
|
||||
end
|
||||
|
||||
function AnimationState:apply (skeleton)
|
||||
if skeleton == nil then error("skeleton cannot be null.", 2) end
|
||||
if self.animationsChanged then self:_animationsChanged() end
|
||||
|
||||
local events = self.events
|
||||
local tracks = self.tracks
|
||||
local queue = self.queue
|
||||
|
||||
for i,current in pairs(tracks) do
|
||||
if not (current == nil or current.delay > 0) then
|
||||
-- Apply mixing from entries first.
|
||||
local mix = current.alpha
|
||||
if current.mixingFrom then mix = mix * applyMixingFrom(current, skeleton) end
|
||||
|
||||
-- Apply current entry.
|
||||
local animationLast = current.animationLast
|
||||
local animationTime = current:getAnimationTime()
|
||||
local timelines = current.animation.timelines
|
||||
if mix == 1 then
|
||||
for i,timeline in ipairs(timelines) do
|
||||
timeline:apply(skeleton, animationLast, animationTime, events, 1, true, false)
|
||||
end
|
||||
else
|
||||
local firstFrame = #current.timelinesRotation == 0
|
||||
local timelinesRotation = current.timelinesRotation;
|
||||
local timelinesFirst = current.timelinesFirst
|
||||
for i,timeline in ipairs(timelines) do
|
||||
if timeline.type == Animation.TimelineType.rotate then
|
||||
self:applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii * 2,
|
||||
firstFrame) -- FIXME passing ii * 2, indexing correct?
|
||||
else
|
||||
timeline:apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false)
|
||||
end
|
||||
end
|
||||
end
|
||||
self:queueEvents(current, animationTime)
|
||||
current.nextAnimationLast = animationTime
|
||||
current.nextTrackLast = current.trackTime
|
||||
end
|
||||
end
|
||||
|
||||
queue:drain()
|
||||
end
|
||||
|
||||
function AnimationState:applyMixingFrom (entry, skeleton)
|
||||
local from = entry.mixingFrom
|
||||
if from.mixingFrom then self:applyMixingFrom(from, skeleton) end
|
||||
|
||||
local mix = 0
|
||||
if entry.mixDuration == 0 then -- Single frame mix to undo mixingFrom changes.
|
||||
mix = 1
|
||||
else
|
||||
mix = entry.mixTime / entry.mixDuration
|
||||
if mix > 1 then mix = 1 end
|
||||
end
|
||||
|
||||
local events = nil
|
||||
if mix < from.eventThreshold then events = self.events end
|
||||
local attachments = mix < from.attachmentThreshold
|
||||
local drawOrder = mix < from.drawOrderThreshold
|
||||
local animationLast = from.animationLast
|
||||
local animationTime = from:getAnimationTime()
|
||||
local timelines = from.animation.timelines
|
||||
local timelinesFirst = from.timelinesFirst;
|
||||
local alpha = from.alpha * entry.mixAlpha * (1 - mix)
|
||||
|
||||
local firstFrame = #from.timelinesRotation.size == 0
|
||||
local timelinesRotation = from.timelinesRotation
|
||||
|
||||
local skip = false
|
||||
for i,timeline in ipairs(timelines) do
|
||||
local setupPose = timelinesFirst[i]
|
||||
if timeline.type == Animation.TimelineType.rotate then
|
||||
self:applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i * 2, firstFrame) -- FIXME passing i * 2, correct indexing?
|
||||
else
|
||||
if not setupPose then
|
||||
if not attachments and timeline.type == Animation.TimelineType.attackment then skip = true end
|
||||
if not drawOrder and timeline.type == Animation.TimelineType.drawOrder then skip = true end
|
||||
end
|
||||
if not skip then timeline:apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true) end
|
||||
end
|
||||
end
|
||||
|
||||
self:queueEvents(from, animationTime)
|
||||
from.nextAnimationLast = animationTime
|
||||
from.nextTrackLast = from.trackTime
|
||||
|
||||
return mix
|
||||
end
|
||||
|
||||
-- CONTINUE WITH applyRotateTimeline here
|
||||
|
||||
return AnimationState
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user