Flip timelines for spine-lua, spine-corona, spine-love.
@ -38,4 +38,3 @@ Runtime:addEventListener("enterFrame", function (event)
|
||||
state:apply(skeleton)
|
||||
skeleton:updateWorldTransform()
|
||||
end)
|
||||
|
||||
|
||||
@ -1,290 +0,0 @@
|
||||
|
||||
dragon.png
|
||||
format: RGBA4444
|
||||
filter: Nearest,Nearest
|
||||
repeat: none
|
||||
L_rear_thigh
|
||||
rotate: false
|
||||
xy: 895, 20
|
||||
size: 91, 148
|
||||
orig: 91, 149
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_wing01
|
||||
rotate: false
|
||||
xy: 814, 672
|
||||
size: 191, 256
|
||||
orig: 191, 256
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_wing02
|
||||
rotate: false
|
||||
xy: 714, 189
|
||||
size: 179, 269
|
||||
orig: 179, 269
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_wing03
|
||||
rotate: false
|
||||
xy: 785, 463
|
||||
size: 186, 207
|
||||
orig: 186, 207
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_wing05
|
||||
rotate: true
|
||||
xy: 2, 9
|
||||
size: 218, 213
|
||||
orig: 218, 213
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_wing06
|
||||
rotate: false
|
||||
xy: 2, 229
|
||||
size: 192, 331
|
||||
orig: 192, 331
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing01
|
||||
rotate: true
|
||||
xy: 502, 709
|
||||
size: 219, 310
|
||||
orig: 219, 310
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing02
|
||||
rotate: true
|
||||
xy: 204, 463
|
||||
size: 203, 305
|
||||
orig: 203, 305
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing03
|
||||
rotate: false
|
||||
xy: 511, 460
|
||||
size: 272, 247
|
||||
orig: 272, 247
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing05
|
||||
rotate: false
|
||||
xy: 196, 232
|
||||
size: 251, 229
|
||||
orig: 251, 229
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing06
|
||||
rotate: false
|
||||
xy: 2, 562
|
||||
size: 200, 366
|
||||
orig: 200, 366
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing07
|
||||
rotate: true
|
||||
xy: 449, 258
|
||||
size: 200, 263
|
||||
orig: 200, 263
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing08
|
||||
rotate: false
|
||||
xy: 467, 2
|
||||
size: 234, 254
|
||||
orig: 234, 254
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing09
|
||||
rotate: false
|
||||
xy: 217, 26
|
||||
size: 248, 204
|
||||
orig: 248, 204
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
back
|
||||
rotate: false
|
||||
xy: 703, 2
|
||||
size: 190, 185
|
||||
orig: 190, 185
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
chest
|
||||
rotate: true
|
||||
xy: 895, 170
|
||||
size: 136, 122
|
||||
orig: 136, 122
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_toeA
|
||||
rotate: false
|
||||
xy: 976, 972
|
||||
size: 29, 50
|
||||
orig: 29, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
head
|
||||
rotate: false
|
||||
xy: 204, 668
|
||||
size: 296, 260
|
||||
orig: 296, 260
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
logo
|
||||
rotate: false
|
||||
xy: 2, 930
|
||||
size: 897, 92
|
||||
orig: 897, 92
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tail01
|
||||
rotate: false
|
||||
xy: 895, 308
|
||||
size: 120, 153
|
||||
orig: 120, 153
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tail03
|
||||
rotate: false
|
||||
xy: 901, 930
|
||||
size: 73, 92
|
||||
orig: 73, 92
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
|
||||
dragon2.png
|
||||
format: RGBA4444
|
||||
filter: Nearest,Nearest
|
||||
repeat: none
|
||||
L_front_leg
|
||||
rotate: true
|
||||
xy: 391, 141
|
||||
size: 84, 57
|
||||
orig: 84, 57
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_front_thigh
|
||||
rotate: false
|
||||
xy: 446, 269
|
||||
size: 84, 72
|
||||
orig: 84, 72
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_rear_leg
|
||||
rotate: true
|
||||
xy: 888, 342
|
||||
size: 168, 132
|
||||
orig: 206, 177
|
||||
offset: 19, 20
|
||||
index: -1
|
||||
L_wing04
|
||||
rotate: false
|
||||
xy: 256, 227
|
||||
size: 188, 135
|
||||
orig: 188, 135
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_wing07
|
||||
rotate: false
|
||||
xy: 2, 109
|
||||
size: 159, 255
|
||||
orig: 159, 255
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_wing08
|
||||
rotate: true
|
||||
xy: 705, 346
|
||||
size: 164, 181
|
||||
orig: 164, 181
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
L_wing09
|
||||
rotate: false
|
||||
xy: 499, 343
|
||||
size: 204, 167
|
||||
orig: 204, 167
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_front_leg
|
||||
rotate: false
|
||||
xy: 273, 34
|
||||
size: 101, 89
|
||||
orig: 101, 89
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_front_thigh
|
||||
rotate: false
|
||||
xy: 163, 106
|
||||
size: 108, 108
|
||||
orig: 108, 108
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_rear_leg
|
||||
rotate: false
|
||||
xy: 273, 125
|
||||
size: 116, 100
|
||||
orig: 116, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_rear_thigh
|
||||
rotate: false
|
||||
xy: 163, 216
|
||||
size: 91, 148
|
||||
orig: 91, 149
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
R_wing04
|
||||
rotate: false
|
||||
xy: 2, 366
|
||||
size: 279, 144
|
||||
orig: 279, 144
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
chin
|
||||
rotate: false
|
||||
xy: 283, 364
|
||||
size: 214, 146
|
||||
orig: 214, 146
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front_toeB
|
||||
rotate: false
|
||||
xy: 590, 284
|
||||
size: 56, 57
|
||||
orig: 56, 57
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-toe
|
||||
rotate: true
|
||||
xy: 2, 2
|
||||
size: 105, 77
|
||||
orig: 109, 77
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tail02
|
||||
rotate: true
|
||||
xy: 151, 9
|
||||
size: 95, 120
|
||||
orig: 95, 120
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tail04
|
||||
rotate: false
|
||||
xy: 532, 270
|
||||
size: 56, 71
|
||||
orig: 56, 71
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tail05
|
||||
rotate: false
|
||||
xy: 648, 282
|
||||
size: 52, 59
|
||||
orig: 52, 59
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
tail06
|
||||
rotate: true
|
||||
xy: 81, 12
|
||||
size: 95, 68
|
||||
orig: 95, 68
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
39
spine-corona/examples/hero.lua
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
-- This skeleton uses IK for the feet.
|
||||
|
||||
local spine = require "spine-corona.spine"
|
||||
|
||||
local json = spine.SkeletonJson.new()
|
||||
local skeletonData = json:readSkeletonDataFile("examples/hero/hero.json")
|
||||
|
||||
local skeleton = spine.Skeleton.new(skeletonData)
|
||||
function skeleton:createImage (attachment)
|
||||
return display.newImage("examples/hero/images/" .. attachment.name .. ".png")
|
||||
end
|
||||
skeleton.group.x = 195
|
||||
skeleton.group.y = 385
|
||||
skeleton.flipX = false
|
||||
skeleton.flipY = false
|
||||
skeleton.debug = true -- Omit or set to false to not draw debug lines on top of the images.
|
||||
skeleton:setToSetupPose()
|
||||
|
||||
-- AnimationStateData defines crossfade durations between animations.
|
||||
local stateData = spine.AnimationStateData.new(skeletonData)
|
||||
-- AnimationState has a queue of animations and can apply them with crossfading.
|
||||
local state = spine.AnimationState.new(stateData)
|
||||
--state:setAnimationByName(0, "Idle", true, 0)
|
||||
state:setAnimationByName(0, "Walk", true, 0)
|
||||
|
||||
local lastTime = 0
|
||||
local animationTime = 0
|
||||
Runtime:addEventListener("enterFrame", function (event)
|
||||
-- Compute time in seconds since last frame.
|
||||
local currentTime = event.time / 1000
|
||||
local delta = currentTime - lastTime
|
||||
lastTime = currentTime
|
||||
|
||||
-- Update the state with the delta time, apply it, and update the world transforms.
|
||||
state:update(delta)
|
||||
state:apply(skeleton)
|
||||
skeleton:updateWorldTransform()
|
||||
end)
|
||||
5
spine-corona/examples/hero/hero.json
Normal file
BIN
spine-corona/examples/hero/images/body.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
spine-corona/examples/hero/images/cape.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
spine-corona/examples/hero/images/eyes.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
spine-corona/examples/hero/images/fingers.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
spine-corona/examples/hero/images/foot1.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
spine-corona/examples/hero/images/foot2.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
spine-corona/examples/hero/images/forearm1.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
spine-corona/examples/hero/images/forearm2.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
spine-corona/examples/hero/images/hand1.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
spine-corona/examples/hero/images/hand2.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
spine-corona/examples/hero/images/head.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
5
spine-corona/examples/hero/images/license.txt
Normal file
@ -0,0 +1,5 @@
|
||||
Copyright (c) 2014, XDTech
|
||||
|
||||
The project file and images in this "Hero" project are provided for
|
||||
demonstration purposes only and may not be redistributed for any reason nor
|
||||
used as the basis for derivative work.
|
||||
BIN
spine-corona/examples/hero/images/mantles.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
spine-corona/examples/hero/images/mouth.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
spine-corona/examples/hero/images/shin1.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
spine-corona/examples/hero/images/shin2.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
spine-corona/examples/hero/images/sword.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
spine-corona/examples/hero/images/thigh1.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
spine-corona/examples/hero/images/thigh2.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
spine-corona/examples/hero/images/upperarm1.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
spine-corona/examples/hero/images/upperarm2.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
@ -1,4 +1,5 @@
|
||||
|
||||
require "examples.spineboy"
|
||||
-- require "examples.spineboy"
|
||||
-- require "examples.goblins"
|
||||
-- require "examples.dragon"
|
||||
require "examples.hero"
|
||||
|
||||
@ -128,10 +128,11 @@ function spine.Skeleton.new (skeletonData, group)
|
||||
end
|
||||
-- Position image based on attachment and bone.
|
||||
if image ~= spine.Skeleton.failed then
|
||||
local flipX, flipY = ((self.flipX and -1) or 1), ((self.flipY and -1) or 1)
|
||||
local bone = slot.bone
|
||||
local flipX, flipY = ((bone.worldFlipX and -1) or 1), ((bone.worldFlipY and -1) or 1)
|
||||
|
||||
local x = slot.bone.worldX + attachment.x * slot.bone.m00 + attachment.y * slot.bone.m01
|
||||
local y = -(slot.bone.worldY + attachment.x * slot.bone.m10 + attachment.y * slot.bone.m11)
|
||||
local x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01
|
||||
local y = -(bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11)
|
||||
if not image.lastX then
|
||||
image.x, image.y = x, y
|
||||
image.lastX, image.lastY = x, y
|
||||
@ -145,16 +146,16 @@ function spine.Skeleton.new (skeletonData, group)
|
||||
-- Fix scaling when attachment is rotated 90 or -90.
|
||||
local rotation = math.abs(attachment.rotation) % 180
|
||||
if (rotation == 90) then
|
||||
xScale = xScale * slot.bone.worldScaleY
|
||||
yScale = yScale * slot.bone.worldScaleX
|
||||
xScale = xScale * bone.worldScaleY
|
||||
yScale = yScale * bone.worldScaleX
|
||||
else
|
||||
xScale = xScale * slot.bone.worldScaleX
|
||||
yScale = yScale * slot.bone.worldScaleY
|
||||
xScale = xScale * bone.worldScaleX
|
||||
yScale = yScale * bone.worldScaleY
|
||||
if rotation ~= 0 and xScale ~= yScale and not image.rotationWarning then
|
||||
image.rotationWarning = true
|
||||
print("WARNING: Non-uniform bone scaling with attachments not rotated to\n"
|
||||
.." cardinal angles will not work as expected with Corona.\n"
|
||||
.." Bone: "..slot.bone.data.name..", slot: "..slot.data.name..", attachment: "..attachment.name)
|
||||
.." Bone: "..bone.data.name..", slot: "..slot.data.name..", attachment: "..attachment.name)
|
||||
end
|
||||
end
|
||||
if not image.lastScaleX then
|
||||
@ -165,7 +166,7 @@ function spine.Skeleton.new (skeletonData, group)
|
||||
image.lastScaleX, image.lastScaleY = xScale, yScale
|
||||
end
|
||||
|
||||
rotation = -(slot.bone.worldRotation + attachment.rotation) * flipX * flipY
|
||||
rotation = -(bone.worldRotation + attachment.rotation) * flipX * flipY
|
||||
if not image.lastRotation then
|
||||
image.rotation = rotation
|
||||
image.lastRotation = rotation
|
||||
@ -199,13 +200,13 @@ function spine.Skeleton.new (skeletonData, group)
|
||||
bone.line.x = bone.worldX
|
||||
bone.line.y = -bone.worldY
|
||||
bone.line.rotation = -bone.worldRotation
|
||||
if self.flipX then
|
||||
if bone.worldFlipX then
|
||||
bone.line.xScale = -1
|
||||
bone.line.rotation = -bone.line.rotation
|
||||
else
|
||||
bone.line.xScale = 1
|
||||
end
|
||||
if self.flipY then
|
||||
if bone.worldFlipY then
|
||||
bone.line.yScale = -1
|
||||
bone.line.rotation = -bone.line.rotation
|
||||
else
|
||||
|
||||
@ -83,6 +83,22 @@ local function binarySearch (values, target, step)
|
||||
end
|
||||
end
|
||||
|
||||
local function binarySearch1 (values, target)
|
||||
local low = 0
|
||||
local high = math.floor(#values - 1)
|
||||
if high == 0 then return 1 end
|
||||
local current = math.floor(high / 2)
|
||||
while true do
|
||||
if values[current + 1] <= target then
|
||||
low = current + 1
|
||||
else
|
||||
high = current
|
||||
end
|
||||
if low == high then return low + 1 end
|
||||
current = math.floor((low + high) / 2)
|
||||
end
|
||||
end
|
||||
|
||||
local function linearSearch (values, target, step)
|
||||
for i = 0, #values, step do
|
||||
if (values[i] > target) then return i end
|
||||
@ -419,7 +435,7 @@ function Animation.AttachmentTimeline.new ()
|
||||
if time >= frames[#frames] then -- Time is after last frame.
|
||||
frameIndex = #frames
|
||||
else
|
||||
frameIndex = binarySearch(frames, time, 1) - 1
|
||||
frameIndex = binarySearch1(frames, time) - 1
|
||||
end
|
||||
|
||||
local attachmentName = self.attachmentNames[frameIndex]
|
||||
@ -477,7 +493,7 @@ function Animation.EventTimeline.new ()
|
||||
if lastTime < frames[0] then
|
||||
frameIndex = 0
|
||||
else
|
||||
frameIndex = binarySearch(frames, lastTime, 1)
|
||||
frameIndex = binarySearch1(frames, lastTime)
|
||||
local frame = frames[frameIndex]
|
||||
while frameIndex > 0 do -- Fire multiple events with the same frame.
|
||||
if frames[frameIndex - 1] ~= frame then break end
|
||||
@ -522,7 +538,7 @@ function Animation.DrawOrderTimeline.new ()
|
||||
if time >= frames[#frames] then -- Time is after last frame.
|
||||
frameIndex = #frames
|
||||
else
|
||||
frameIndex = binarySearch(frames, time, 1) - 1
|
||||
frameIndex = binarySearch1(frames, time) - 1
|
||||
end
|
||||
|
||||
local drawOrder = skeleton.drawOrder
|
||||
@ -542,4 +558,147 @@ function Animation.DrawOrderTimeline.new ()
|
||||
return self
|
||||
end
|
||||
|
||||
Animation.FfdTimeline = {}
|
||||
function Animation.FfdTimeline.new ()
|
||||
local self = Animation.CurveTimeline.new()
|
||||
self.frames = {}
|
||||
self.frameVertices = {}
|
||||
self.slotIndex = -1
|
||||
|
||||
function self:getDuration ()
|
||||
return self.frames[#self.frames]
|
||||
end
|
||||
|
||||
function self:getFrameCount ()
|
||||
return #self.frames + 1
|
||||
end
|
||||
|
||||
function self:setFrame (frameIndex, time, vertices)
|
||||
self.frames[frameIndex] = time
|
||||
self.frameVertices[frameIndex] = vertices
|
||||
end
|
||||
|
||||
function self:apply (skeleton, lastTime, time, firedEvents, alpha)
|
||||
local slot = skeleton.slots[self.slotIndex]
|
||||
if slot.attachment ~= attachment then return end
|
||||
|
||||
local frames = self.frames
|
||||
if time < frames[0] then -- Time is before first frame.
|
||||
slot.attachmentVerticesCount = 0
|
||||
return
|
||||
end
|
||||
|
||||
local frameVertices = self.frameVertices
|
||||
local vertexCount = #frameVertices[0]
|
||||
local vertices = slot.attachmentVertices
|
||||
if #vertices < vertexCount then
|
||||
vertices = {}
|
||||
vertices[vertexCount] = 0
|
||||
slot.attachmentVertices = vertices
|
||||
elseif #vertices < vertexCount then
|
||||
alpha = 1 -- Don't mix from uninitialized slot vertices.
|
||||
end
|
||||
slot.attachmentVerticesCount = vertexCount
|
||||
|
||||
if time >= frames[#frames] then -- Time is after last frame.
|
||||
local lastVertices = frameVertices[#frames.Length]
|
||||
if alpha < 1 then
|
||||
for i = 0, vertexCount do
|
||||
local vertex = vertices[i]
|
||||
vertices[i] = vertex + (lastVertices[i] - vertex) * alpha
|
||||
end
|
||||
else
|
||||
for i = 0, vertexCount do
|
||||
vertices[i] = lastVertices[i]
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Interpolate between the previous frame and the current frame.
|
||||
local frameIndex = binarySearch1(frames, time)
|
||||
local frameTime = frames[frameIndex]
|
||||
local percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime)
|
||||
if percent < 0 then percent = 0 elseif percent > 1 then percent = 1 end
|
||||
percent = self:getCurvePercent(frameIndex - 1, percent)
|
||||
|
||||
local prevVertices = frameVertices[frameIndex - 1]
|
||||
local nextVertices = frameVertices[frameIndex]
|
||||
|
||||
if alpha < 1 then
|
||||
for i = 0, vertexCount do
|
||||
local prev = prevVertices[i]
|
||||
local vertices = vertices[i]
|
||||
vertices[i] = vertices + (prev + (nextVertices[i] - prev) * percent - vertices) * alpha
|
||||
end
|
||||
else
|
||||
for i = 0, vertexCount do
|
||||
local prev = prevVertices[i]
|
||||
vertices[i] = prev + (nextVertices[i] - prev) * percent
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
Animation.FlipXTimeline = {}
|
||||
function Animation.FlipXTimeline.new ()
|
||||
local self = {
|
||||
frames = {}, -- time, flip, ...
|
||||
boneIndex = -1
|
||||
}
|
||||
|
||||
function self:getDuration ()
|
||||
return self.frames[#self.frames - 1]
|
||||
end
|
||||
|
||||
function self:getFrameCount ()
|
||||
return (#self.frames + 1) / 2
|
||||
end
|
||||
|
||||
function self:setFrame (frameIndex, time, flip)
|
||||
frameIndex = frameIndex * 2
|
||||
self.frames[frameIndex] = time
|
||||
self.frames[frameIndex + 1] = flip
|
||||
end
|
||||
|
||||
function self:apply (skeleton, lastTime, time, firedEvents, alpha)
|
||||
local frames = self.frames
|
||||
if time < frames[0] then
|
||||
if lastTime > time then self:apply(skeleton, lastTime, 999999, null, 0) end
|
||||
return
|
||||
elseif lastTime > time then
|
||||
lastTime = -1
|
||||
end
|
||||
|
||||
local frameIndex
|
||||
if time >= frames[#frames - 1] then
|
||||
frameIndex = #frames - 1
|
||||
else
|
||||
frameIndex = binarySearch(frames, time, 2) - 2
|
||||
end
|
||||
if frames[frameIndex] < lastTime then return end
|
||||
|
||||
self:setFlip(skeleton.bones[self.boneIndex], frames[frameIndex + 1])
|
||||
end
|
||||
|
||||
function self:setFlip (bone, flip)
|
||||
bone.flipX = flip
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
Animation.FlipYTimeline = {}
|
||||
function Animation.FlipYTimeline.new ()
|
||||
local self = Animation.FlipXTimeline.new()
|
||||
|
||||
function self:setFlip (bone, flip)
|
||||
bone.flipY = flip
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return Animation
|
||||
|
||||
@ -30,19 +30,23 @@
|
||||
|
||||
local Bone = {}
|
||||
|
||||
function Bone.new (data, parent)
|
||||
function Bone.new (data, skeleton, parent)
|
||||
if not data then error("data cannot be nil", 2) end
|
||||
|
||||
if not skeleton then error("skeleton cannot be nil", 2) end
|
||||
|
||||
local self = {
|
||||
data = data,
|
||||
skeleton = skeleton,
|
||||
parent = parent,
|
||||
x = 0, y = 0,
|
||||
rotation = 0,
|
||||
scaleX = 1, scaleY = 1,
|
||||
flipX = false, flipY = false,
|
||||
m00 = 0, m01 = 0, worldX = 0, -- a b x
|
||||
m10 = 0, m11 = 0, worldY = 0, -- c d y
|
||||
worldRotation = 0,
|
||||
worldScaleX = 1, worldScaleY = 1,
|
||||
worldFlipX = false, worldFlipY = false,
|
||||
}
|
||||
|
||||
function self:updateWorldTransform (flipX, flipY)
|
||||
@ -62,13 +66,16 @@ function Bone.new (data, parent)
|
||||
else
|
||||
self.worldRotation = self.rotation
|
||||
end
|
||||
self.worldFlipX = parent.worldFlipX ~= self.flipX
|
||||
self.worldFlipY = parent.worldFlipY ~= self.flipY
|
||||
else
|
||||
if flipX then
|
||||
local skeletonFlipX, skeletonFlipY = self.skeleton.flipX, self.skeleton.flipY
|
||||
if skeletonFlipX then
|
||||
self.worldX = -self.x
|
||||
else
|
||||
self.worldX = self.x
|
||||
end
|
||||
if flipY then
|
||||
if skeletonFlipY then
|
||||
self.worldY = -self.y
|
||||
else
|
||||
self.worldY = self.y
|
||||
@ -76,21 +83,25 @@ function Bone.new (data, parent)
|
||||
self.worldScaleX = self.scaleX
|
||||
self.worldScaleY = self.scaleY
|
||||
self.worldRotation = self.rotation
|
||||
self.worldFlipX = skeletonFlipX ~= self.flipX
|
||||
self.worldFlipY = skeletonFlipY ~= self.flipY
|
||||
end
|
||||
local radians = math.rad(self.worldRotation)
|
||||
local cos = math.cos(radians)
|
||||
local sin = math.sin(radians)
|
||||
self.m00 = cos * self.worldScaleX
|
||||
self.m10 = sin * self.worldScaleX
|
||||
self.m01 = -sin * self.worldScaleY
|
||||
self.m11 = cos * self.worldScaleY
|
||||
if flipX then
|
||||
self.m00 = -self.m00
|
||||
self.m01 = -self.m01
|
||||
if self.worldFlipX then
|
||||
self.m00 = -cos * self.worldScaleX
|
||||
self.m01 = sin * self.worldScaleY
|
||||
else
|
||||
self.m00 = cos * self.worldScaleX
|
||||
self.m01 = -sin * self.worldScaleY
|
||||
end
|
||||
if flipY then
|
||||
self.m10 = -self.m10
|
||||
self.m11 = -self.m11
|
||||
if self.worldFlipY then
|
||||
self.m10 = -sin * self.worldScaleX
|
||||
self.m11 = -cos * self.worldScaleY
|
||||
else
|
||||
self.m10 = sin * self.worldScaleX
|
||||
self.m11 = cos * self.worldScaleY
|
||||
end
|
||||
end
|
||||
|
||||
@ -101,6 +112,8 @@ function Bone.new (data, parent)
|
||||
self.rotation = data.rotation
|
||||
self.scaleX = data.scaleX
|
||||
self.scaleY = data.scaleY
|
||||
self.flipX = data.flipX
|
||||
self.flipY = data.flipY
|
||||
end
|
||||
|
||||
self:setToSetupPose()
|
||||
|
||||
@ -51,7 +51,7 @@ function Skeleton.new (skeletonData)
|
||||
|
||||
function self:updateWorldTransform ()
|
||||
for i,bone in ipairs(self.bones) do
|
||||
bone:updateWorldTransform(self.flipX, self.flipY)
|
||||
bone:updateWorldTransform()
|
||||
end
|
||||
end
|
||||
|
||||
@ -165,12 +165,12 @@ function Skeleton.new (skeletonData)
|
||||
for i,boneData in ipairs(skeletonData.bones) do
|
||||
local parent
|
||||
if boneData.parent then parent = self.bones[spine.utils.indexOf(skeletonData.bones, boneData.parent)] end
|
||||
table.insert(self.bones, Bone.new(boneData, parent))
|
||||
table.insert(self.bones, Bone.new(boneData, self, parent))
|
||||
end
|
||||
|
||||
for i,slotData in ipairs(skeletonData.slots) do
|
||||
local bone = self.bones[spine.utils.indexOf(skeletonData.bones, slotData.boneData)]
|
||||
local slot = Slot.new(slotData, self, bone)
|
||||
local slot = Slot.new(slotData, bone)
|
||||
table.insert(self.slots, slot)
|
||||
self.slotsByName[slot.data.name] = slot
|
||||
table.insert(self.drawOrder, slot)
|
||||
|
||||
@ -86,6 +86,8 @@ function SkeletonJson.new (attachmentLoader)
|
||||
else
|
||||
boneData.scaleY = 1
|
||||
end
|
||||
boneData.flipX = boneMap["flipX"] or false
|
||||
boneData.flipY = boneMap["flipY"] or false
|
||||
if boneMap["inheritScale"] == false then
|
||||
boneData.inheritScale = false
|
||||
else
|
||||
@ -375,6 +377,27 @@ function SkeletonJson.new (attachmentLoader)
|
||||
table.insert(timelines, timeline)
|
||||
duration = math.max(duration, timeline:getDuration())
|
||||
|
||||
elseif timelineName == "flipX" or timelineName == "flipY" then
|
||||
local x = timelineName == "flipX"
|
||||
local timeline, field
|
||||
if x then
|
||||
timeline = Animation.FlipXTimeline.new()
|
||||
field = "x"
|
||||
else
|
||||
timeline = Animation.FlipYTimeline.new();
|
||||
field = "y"
|
||||
end
|
||||
timeline.boneIndex = boneIndex
|
||||
|
||||
local frameIndex = 0
|
||||
for i,valueMap in ipairs(values) do
|
||||
local flip
|
||||
timeline:setFrame(frameIndex, valueMap["time"], valueMap[field] or false)
|
||||
frameIndex = frameIndex + 1
|
||||
end
|
||||
table.insert(timelines, timeline)
|
||||
duration = math.max(duration, timeline:getDuration())
|
||||
|
||||
else
|
||||
error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")")
|
||||
end
|
||||
|
||||
@ -29,19 +29,18 @@
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local Slot = {}
|
||||
function Slot.new (slotData, skeleton, bone)
|
||||
function Slot.new (slotData, bone)
|
||||
if not slotData then error("slotData cannot be nil", 2) end
|
||||
if not skeleton then error("skeleton cannot be nil", 2) end
|
||||
if not bone then error("bone cannot be nil", 2) end
|
||||
|
||||
local self = {
|
||||
data = slotData,
|
||||
skeleton = skeleton,
|
||||
bone = bone,
|
||||
r = 1, g = 1, b = 1, a = 1,
|
||||
attachment = nil,
|
||||
attachmentTime = 0,
|
||||
attachmentVertices = nil
|
||||
attachmentVertices = nil,
|
||||
attachmentVerticesCount = 0
|
||||
}
|
||||
|
||||
function self:setColor (r, g, b, a)
|
||||
@ -53,15 +52,16 @@ function Slot.new (slotData, skeleton, bone)
|
||||
|
||||
function self:setAttachment (attachment)
|
||||
self.attachment = attachment
|
||||
self.attachmentTime = self.skeleton.time
|
||||
self.attachmentTime = self.bone.skeleton.time
|
||||
self.attachmentVerticesCount = 0
|
||||
end
|
||||
|
||||
function self:setAttachmentTime (time)
|
||||
self.attachmentTime = self.skeleton.time - time
|
||||
self.attachmentTime = self.bone.skeleton.time - time
|
||||
end
|
||||
|
||||
function self:getAttachmentTime ()
|
||||
return self.skeleton.time - self.attachmentTime
|
||||
return self.bone.skeleton.time - self.attachmentTime
|
||||
end
|
||||
|
||||
function self:setToSetupPose ()
|
||||
@ -71,7 +71,7 @@ function Slot.new (slotData, skeleton, bone)
|
||||
|
||||
local attachment
|
||||
if data.attachmentName then
|
||||
attachment = self.skeleton:getAttachment(data.name, data.attachmentName)
|
||||
attachment = self.bone.skeleton:getAttachment(data.name, data.attachmentName)
|
||||
end
|
||||
self:setAttachment(attachment)
|
||||
end
|
||||
|
||||