Coding Spine Runtime Limb and Skeleton Control

Hi All,

I am struggling to control spine runtime skeletons in corona SDK

if your not aware of spine you can look at run time code here

http://esotericsoftware.com/spine-using-runtimes/#manipulating-bones

I can create the character from the demo code, but want to interact with object, eg manipulate whole character or limbs with touch events. But i cant figure out how to. Can someone please help?

heres my code so far 

-- heres the character creation  local json = spine.SkeletonJson.new() local skeletonData = json:readSkeletonDataFile("goblin.json") local skeleton = spine.Skeleton.new(skeletonData) -- if i want to move then whole skeleton i tried the following -- touch listener function function skeleton:touch( event )     if event.phase == "began" then              self.markX = self.x    -- store x location of object         self.markY = self.y    -- store y location of object          elseif event.phase == "moved" then              local x = (event.x - event.xStart) + self.markX         local y = (event.y - event.yStart) + self.markY                  self.x, self.y = x, y    -- move object based on calculations above     end          return true end -- make 'skeleton' listen for touch events skeleton:addEventListener( "touch", skeleton ) -- How would i reference an individual limb and move that wit a touch event local rightLeg = skeleton:findBone("right upper leg")  

your help would be much appreciated

Nick

No responses yet, but i am interested to see if this is the right way to approach spine sprite runtime control.  

I looked though the corona runtimes and noticed that you can add the skeleton to a corona group when creating a new skeleton. See below code.

What i would like to solve now is allow an individual limb to be controlled by a touch event. Eg make a leg rotate at hip. Does anyone have any suggestions how to reference specific limb of skeleton for touch events?

The following code allows the spine character now to be dragged around the screen.

local json = spine.SkeletonJson.new() local skeletonData = json:readSkeletonDataFile("goblin.json") -- add the skeleton to a touchable data file -- the key here is to create a new displaygroup in corona local skelGroup = display.newGroup() local skeleton = spine.Skeleton.new(skeletonData,skelGroup ) -- touch listener function function skelGroup:touch( event )     if event.phase == "began" then              self.markX = self.x    -- store x location of object         self.markY = self.y    -- store y location of object          elseif event.phase == "moved" then              local x = (event.x - event.xStart) + self.markX         local y = (event.y - event.yStart) + self.markY                  self.x, self.y = x, y    -- move object based on calculations above     end          return true end -- make 'skeleton' listen for touch events skelGroup:addEventListener( "touch", skelGroup )

No responses yet, but i am interested to see if this is the right way to approach spine sprite runtime control.  

I looked though the corona runtimes and noticed that you can add the skeleton to a corona group when creating a new skeleton. See below code.

What i would like to solve now is allow an individual limb to be controlled by a touch event. Eg make a leg rotate at hip. Does anyone have any suggestions how to reference specific limb of skeleton for touch events?

The following code allows the spine character now to be dragged around the screen.

local json = spine.SkeletonJson.new() local skeletonData = json:readSkeletonDataFile("goblin.json") -- add the skeleton to a touchable data file -- the key here is to create a new displaygroup in corona local skelGroup = display.newGroup() local skeleton = spine.Skeleton.new(skeletonData,skelGroup ) -- touch listener function function skelGroup:touch( event )     if event.phase == "began" then              self.markX = self.x    -- store x location of object         self.markY = self.y    -- store y location of object          elseif event.phase == "moved" then              local x = (event.x - event.xStart) + self.markX         local y = (event.y - event.yStart) + self.markY                  self.x, self.y = x, y    -- move object based on calculations above     end          return true end -- make 'skeleton' listen for touch events skelGroup:addEventListener( "touch", skelGroup )

I am also struggling to use Spine with Corona SDK.  However, my trouble is a scene change.  It seems to me the Spineboy example looks like it works okay till you try and put it into a real environment that needs a scene change.  It is acting as if it has no way to work with Storyboard scene change.  No matter what,  the spineboy character stays onscreen during a scene change.  Can someone please show me what are the exact calls I need to make to get the Spineboy Character to gracefully stop and go away for a scene change, then come back and have it work properly again in a new scene.  

 told to use Runtime:removeEventListener , but did not say what exactly it needs to be used on.

 I have tried Runtime:removeEventListener all listeners already, no luck

For this example I am using Corona Storyboard here:  

https://github.com/alterant-kr/_GameTemplate-with-storyboard  combined with Spineboy and Corona Runtime here

https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-corona

below is the spineboy.lua but I think there are other files that need remove EventListener called on?

– This example shows simple usage of displaying a skeleton with queued animations.

local spine = require “spine-corona.spine”

local json = spine.SkeletonJson.new()

json.scale = 1

local skeletonData = json:readSkeletonDataFile(“examples/spineboy/spineboy.json”)

local skeleton = spine.Skeleton.new(skeletonData)

function skeleton:createImage (attachment)

        – Customize where images are loaded.

        return display.newImage(“examples/spineboy/images/” … attachment.name … “.png”)

end

skeleton.group.x = 150

skeleton.group.y = 325

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.debugAabb = true

skeleton:setToSetupPose()

local bounds = spine.SkeletonBounds.new()

– AnimationStateData defines crossfade durations between animations.

local stateData = spine.AnimationStateData.new(skeletonData)

stateData:setMix(“walk”, “jump”, 0.2)

stateData:setMix(“jump”, “walk”, 0.4)

– AnimationState has a queue of animations and can apply them with crossfading.

local state = spine.AnimationState.new(stateData)

state:setAnimationByName(0, “drawOrder”)

state:addAnimationByName(0, “jump”, false, 0)

state:addAnimationByName(0, “walk”, true, 0)

state.onStart = function (trackIndex)

        print(trackIndex…" start: "…state:getCurrent(trackIndex).animation.name)

end

state.onEnd = function (trackIndex)

        print(trackIndex…" end: "…state:getCurrent(trackIndex).animation.name)

end

state.onComplete = function (trackIndex, loopCount)

        print(trackIndex…" complete: “…state:getCurrent(trackIndex).animation.name…”, "…loopCount)

end

state.onEvent = function (trackIndex, event)

        print(trackIndex…" event: “…state:getCurrent(trackIndex).animation.name…”, “…event.data.name…”, “…event.intValue…”, “…event.floatValue…”, ‘"…(event.stringValue or “”)…"’")

end

local lastTime = 0

local touchX = 999999

local touchY = 999999

local headSlot = skeleton:findSlot(“head”)

Runtime:addEventListener(“enterFrame”, function (event)

        – Compute time in seconds since last frame.

        local currentTime = event.time / 1000

        local delta = currentTime - lastTime

        lastTime = currentTime

        – Bounding box hit detection.

        bounds:update(skeleton, true)

        if bounds:containsPoint(touchX, touchY) then

                headSlot.g = 0;

                headSlot.b = 0;

        else

                headSlot.g = 1;

                headSlot.b = 1;

        end

        – Update the state with the delta time, apply it, and update the world transforms.

        state:update(delta)

        state:apply(skeleton)

        skeleton:updateWorldTransform()

end)

Runtime:addEventListener(“touch”, function (event)

        if event.phase ~= “ended” and event.phase ~= “cancelled” then

                – Make the coordinates relative to the skeleton’s group.

                touchX = event.x - skeleton.group.x

                touchY = skeleton.group.y - event.y

        else

                touchX = 999999

                touchY = 999999

        end

end)

I am also struggling to use Spine with Corona SDK.  However, my trouble is a scene change.  It seems to me the Spineboy example looks like it works okay till you try and put it into a real environment that needs a scene change.  It is acting as if it has no way to work with Storyboard scene change.  No matter what,  the spineboy character stays onscreen during a scene change.  Can someone please show me what are the exact calls I need to make to get the Spineboy Character to gracefully stop and go away for a scene change, then come back and have it work properly again in a new scene.  

 told to use Runtime:removeEventListener , but did not say what exactly it needs to be used on.

 I have tried Runtime:removeEventListener all listeners already, no luck

For this example I am using Corona Storyboard here:  

https://github.com/alterant-kr/_GameTemplate-with-storyboard  combined with Spineboy and Corona Runtime here

https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-corona

below is the spineboy.lua but I think there are other files that need remove EventListener called on?

– This example shows simple usage of displaying a skeleton with queued animations.

local spine = require “spine-corona.spine”

local json = spine.SkeletonJson.new()

json.scale = 1

local skeletonData = json:readSkeletonDataFile(“examples/spineboy/spineboy.json”)

local skeleton = spine.Skeleton.new(skeletonData)

function skeleton:createImage (attachment)

        – Customize where images are loaded.

        return display.newImage(“examples/spineboy/images/” … attachment.name … “.png”)

end

skeleton.group.x = 150

skeleton.group.y = 325

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.debugAabb = true

skeleton:setToSetupPose()

local bounds = spine.SkeletonBounds.new()

– AnimationStateData defines crossfade durations between animations.

local stateData = spine.AnimationStateData.new(skeletonData)

stateData:setMix(“walk”, “jump”, 0.2)

stateData:setMix(“jump”, “walk”, 0.4)

– AnimationState has a queue of animations and can apply them with crossfading.

local state = spine.AnimationState.new(stateData)

state:setAnimationByName(0, “drawOrder”)

state:addAnimationByName(0, “jump”, false, 0)

state:addAnimationByName(0, “walk”, true, 0)

state.onStart = function (trackIndex)

        print(trackIndex…" start: "…state:getCurrent(trackIndex).animation.name)

end

state.onEnd = function (trackIndex)

        print(trackIndex…" end: "…state:getCurrent(trackIndex).animation.name)

end

state.onComplete = function (trackIndex, loopCount)

        print(trackIndex…" complete: “…state:getCurrent(trackIndex).animation.name…”, "…loopCount)

end

state.onEvent = function (trackIndex, event)

        print(trackIndex…" event: “…state:getCurrent(trackIndex).animation.name…”, “…event.data.name…”, “…event.intValue…”, “…event.floatValue…”, ‘"…(event.stringValue or “”)…"’")

end

local lastTime = 0

local touchX = 999999

local touchY = 999999

local headSlot = skeleton:findSlot(“head”)

Runtime:addEventListener(“enterFrame”, function (event)

        – Compute time in seconds since last frame.

        local currentTime = event.time / 1000

        local delta = currentTime - lastTime

        lastTime = currentTime

        – Bounding box hit detection.

        bounds:update(skeleton, true)

        if bounds:containsPoint(touchX, touchY) then

                headSlot.g = 0;

                headSlot.b = 0;

        else

                headSlot.g = 1;

                headSlot.b = 1;

        end

        – Update the state with the delta time, apply it, and update the world transforms.

        state:update(delta)

        state:apply(skeleton)

        skeleton:updateWorldTransform()

end)

Runtime:addEventListener(“touch”, function (event)

        if event.phase ~= “ended” and event.phase ~= “cancelled” then

                – Make the coordinates relative to the skeleton’s group.

                touchX = event.x - skeleton.group.x

                touchY = skeleton.group.y - event.y

        else

                touchX = 999999

                touchY = 999999

        end

end)