main.lua 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. -------------------------------------------------------------------------------
  2. -- Spine Runtimes License Agreement
  3. -- Last updated January 1, 2020. Replaces all prior versions.
  4. --
  5. -- Copyright (c) 2013-2020, Esoteric Software LLC
  6. --
  7. -- Integration of the Spine Runtimes into software or otherwise creating
  8. -- derivative works of the Spine Runtimes is permitted under the terms and
  9. -- conditions of Section 2 of the Spine Editor License Agreement:
  10. -- http://esotericsoftware.com/spine-editor-license
  11. --
  12. -- Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. -- or otherwise create derivative works of the Spine Runtimes (collectively,
  14. -- "Products"), provided that each user of the Products must obtain their own
  15. -- Spine Editor license and redistribution of the Products in any form must
  16. -- include this license and copyright notice.
  17. --
  18. -- THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. -- DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. -- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. -- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. -- BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. -- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. -- THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. -------------------------------------------------------------------------------
  29. require("mobdebug").start()
  30. local spine = require "spine-solar2d.spine"
  31. local skeletons = {}
  32. local activeSkeleton = 1
  33. local lastTime = 0
  34. local swirl = spine.SwirlEffect.new(400)
  35. local swirlTime = 0
  36. function loadSkeleton(atlasFile, jsonFile, x, y, scale, animation, skin)
  37. -- to load an atlas, we need to define a function that returns
  38. -- a Corona paint object. This allows you to resolve images
  39. -- however you see fit
  40. local imageLoader = function (path)
  41. local paint = { type = "image", filename = "data/" .. path }
  42. return paint
  43. end
  44. -- load the atlas
  45. local atlas = spine.TextureAtlas.new(spine.utils.readFile("data/" .. atlasFile), imageLoader)
  46. -- load the JSON and create a Skeleton from it
  47. local json = spine.SkeletonJson.new(spine.AtlasAttachmentLoader.new(atlas))
  48. json.scale = scale
  49. local skeletonData = json:readSkeletonDataFile("data/" .. jsonFile)
  50. local skeleton = spine.Skeleton.new(skeletonData)
  51. skeleton.scaleY = -1 -- Corona's coordinate system has its y-axis point downwards
  52. skeleton.group.x = x
  53. skeleton.group.y = y
  54. -- Set the skin if we got one
  55. if skin then skeleton:setSkin(skin) end
  56. -- create an animation state object to apply animations to the skeleton
  57. local animationStateData = spine.AnimationStateData.new(skeletonData)
  58. animationStateData.defaultMix = 0.5
  59. local animationState = spine.AnimationState.new(animationStateData)
  60. -- set the skeleton invisible
  61. skeleton.group.isVisible = false
  62. -- set a name on the group of the skeleton so we can find it during debugging
  63. skeleton.group.name = jsonFile
  64. -- set some event callbacks
  65. animationState.onStart = function (entry)
  66. print(entry.trackIndex.." start: "..entry.animation.name)
  67. end
  68. animationState.onInterrupt = function (entry)
  69. print(entry.trackIndex.." interrupt: "..entry.animation.name)
  70. end
  71. animationState.onEnd = function (entry)
  72. print(entry.trackIndex.." end: "..entry.animation.name)
  73. end
  74. animationState.onComplete = function (entry)
  75. print(entry.trackIndex.." complete: "..entry.animation.name)
  76. end
  77. animationState.onDispose = function (entry)
  78. print(entry.trackIndex.." dispose: "..entry.animation.name)
  79. end
  80. animationState.onEvent = function (entry, event)
  81. print(entry.trackIndex.." event: "..entry.animation.name..", "..event.data.name..", "..event.intValue..", "..event.floatValue..", '"..(event.stringValue or "").."'" .. ", " .. event.volume .. ", " .. event.balance)
  82. end
  83. if atlasFile == "spineboy.atlas" then
  84. animationStateData:setMix("walk", "jump", 0.4)
  85. animationStateData:setMix("jump", "run", 0.4);
  86. animationState:setAnimationByName(0, "walk", true)
  87. local jumpEntry = animationState:addAnimationByName(0, "jump", false, 3)
  88. animationState:addAnimationByName(0, "run", true, 0)
  89. elseif atlasFile == "raptor.atlas" then
  90. --skeleton.vertexEffect = spine.JitterEffect.new(5, 5)
  91. skeleton.vertexEffect = swirl
  92. animationState:setAnimationByName(0, animation, true)
  93. elseif jsonFile == "mix-and-match-pro.json" then
  94. -- Create a new skin, by mixing and matching other skins
  95. -- that fit together. Items making up the girl are individual
  96. -- skins. Using the skin API, a new skin is created which is
  97. -- a combination of all these individual item skins.
  98. local skin = spine.Skin.new("mix-and-match")
  99. skin:addSkin(skeletonData:findSkin("skin-base"))
  100. skin:addSkin(skeletonData:findSkin("nose/short"))
  101. skin:addSkin(skeletonData:findSkin("eyelids/girly"))
  102. skin:addSkin(skeletonData:findSkin("eyes/violet"))
  103. skin:addSkin(skeletonData:findSkin("hair/brown"))
  104. skin:addSkin(skeletonData:findSkin("clothes/hoodie-orange"))
  105. skin:addSkin(skeletonData:findSkin("legs/pants-jeans"))
  106. skin:addSkin(skeletonData:findSkin("accessories/bag"))
  107. skin:addSkin(skeletonData:findSkin("accessories/hat-red-yellow"))
  108. skeleton:setSkinByReference(skin)
  109. animationState:setAnimationByName(0, animation, true)
  110. else
  111. animationState:setAnimationByName(0, animation, true)
  112. end
  113. -- return the skeleton an animation state
  114. return { skeleton = skeleton, state = animationState }
  115. end
  116. table.insert(skeletons, loadSkeleton("mix-and-match.atlas", "mix-and-match-pro.json", 240, 300, 0.3, "dance"))
  117. table.insert(skeletons, loadSkeleton("spineboy.atlas", "spineboy-pro.json", 240, 300, 0.4, "walk"))
  118. table.insert(skeletons, loadSkeleton("stretchyman.atlas", "stretchyman-pro.json", 40, 300, 0.5, "sneak"))
  119. table.insert(skeletons, loadSkeleton("coin.atlas", "coin-pro.json", 240, 160, 0.4, "animation"))
  120. table.insert(skeletons, loadSkeleton("raptor.atlas", "raptor-pro.json", 200, 300, 0.25, "walk"))
  121. table.insert(skeletons, loadSkeleton("goblins.atlas", "goblins-pro.json", 240, 300, 0.8, "walk", "goblin"))
  122. table.insert(skeletons, loadSkeleton("tank.atlas", "tank-pro.json", 400, 300, 0.2, "drive"))
  123. table.insert(skeletons, loadSkeleton("vine.atlas", "vine-pro.json", 240, 300, 0.3, "grow"))
  124. local triangulator = spine.Triangulator.new()
  125. local polygon = { 411, 219, 199, 230, 161, 362, 534, 407, 346, 305, 596, 265 }
  126. local indices = triangulator:triangulate(polygon)
  127. print(indices)
  128. print(triangulator:decompose(polygon, indices))
  129. local skeletonClipping = spine.SkeletonClipping.new()
  130. local polygon2 = {0, 0, 100, 0, 100, 100, 0, 100 }
  131. skeletonClipping:makeClockwise(polygon2)
  132. print(polygon2)
  133. local bounds = spine.SkeletonBounds.new()
  134. skeletons[1].skeleton:updateWorldTransform()
  135. bounds:update(skeletons[1].skeleton, true)
  136. local offset = {}
  137. local size = {}
  138. skeletons[1].skeleton:getBounds(offset, size)
  139. display.setDefault("background", 0.2, 0.2, 0.2, 1)
  140. Runtime:addEventListener("enterFrame", function (event)
  141. local currentTime = event.time / 1000
  142. local delta = currentTime - lastTime
  143. lastTime = currentTime
  144. swirlTime = swirlTime + delta
  145. local percent = swirlTime % 2
  146. if (percent > 1) then percent = 1 - (percent - 1) end
  147. swirl.angle = spine.Interpolation.apply(spine.Interpolation.pow2, -60, 60, percent)
  148. skeleton = skeletons[activeSkeleton].skeleton
  149. skeleton.group.isVisible = true
  150. state = skeletons[activeSkeleton].state
  151. state:update(delta)
  152. state:apply(skeleton)
  153. skeleton:updateWorldTransform()
  154. -- uncomment if you want to know how many batches a skeleton renders to
  155. -- print(skeleton.batches)
  156. end)
  157. Runtime:addEventListener("key", function(event)
  158. if activeSkeleton == 2 and event.phase == "down" then
  159. state = skeletons[activeSkeleton].state
  160. state:setAnimationByName(0, "jump", false)
  161. state:addAnimationByName(0, "walk", true, 0)
  162. end
  163. return false
  164. end)
  165. Runtime:addEventListener("tap", function(event)
  166. skeletons[activeSkeleton].skeleton.group.isVisible = false
  167. activeSkeleton = activeSkeleton + 1
  168. if activeSkeleton > #skeletons then activeSkeleton = 1 end
  169. skeletons[activeSkeleton].skeleton.group.isVisible = true
  170. end)