• Runtimes
  • [Corona] Help to position bounding box on a bone

Related Discussions
...

Hi,

I've spent holiday break learning Spine, and the only thing I haven't figured out how to do, is how to attach a binding box to a bone so I can apply physics to it. I

I've read other forum posts related to other runtimes and I know that realWorldX = bone.worldX + skeleton.x and I tried to do that in the code below but my bounding box is still attached to the skeleton's origin.

Also, I had to fix the rotation by 90 degrees as it was not position correctly, so I'm sure I'm doing something wrong in my code



---

 PHYSICS METHOD 1 

---




---

 USING BOUNDING BOXES 

---




---


local bounds = spine.SkeletonBounds.new()
bounds:update(skeleton, true)

local vertices1 = skeleton:getAttachment ("bb-torso", "bb-torso").vertices
local bone1 = skeleton:findBone ("torso")

local polygon1 = display.newPolygon (skeleton.group, 0, 0, vertices1)
polygon1:setFillColor(0, 0, 1, 1)
polygon1.strokeWidth = 1
polygon1:setStrokeColor(1, 0, 0, 1)
polygon1.x = bone1.data.x + bone1.parent.worldX
polygon1.y = -bone1.data.y + bone1.parent.worldY
polygon1.rotation = -90
physics.addBody(polygon1, "static")

and here is the enterFrame function in case is needed, I have this block of code before the SkeletonBounds, vertices and the polygon

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)

Here is the image of spineBoy where you can see how the torso gets attached to the skeleton's origin

Image removed due to the lack of support for HTTPS. | Show Anyway

Could you plese help me position my bounding box correctly?

Thanks in advance, I'm one of the backers of the original Kickstarter project, but it wasn't until this holiday break that I had time to go deep into learning Spine. Congratulations for making such a brilliant piece of software

Regards
Hector

7 dias depois

Sorry I didn't get to this sooner so you'd have more time during the holidays to play. 🙁

The vertices on a bounding box attachment are relative to the bone the attachment is attached to. The bone's world transform needs to be applied to position the polygon in the right place:

local worldVertices = {}
boundingBox:computeWorldVertices(skeleton.x, skeleton.y, slot.bone, worldVertices)

Then you would draw worldVertices. I see you want to use a Corona polygon though. In that case it would be something like (untested):

local torso = skeleton:findBone("torso")
local vertices = skeleton:getAttachment ("bb-torso", "bb-torso").vertices
local polygon = display.newPolygon(skeleton.group, 0, 0, vertices)
polygon:setFillColor(0, 0, 1, 1)
polygon.strokeWidth = 1
polygon:setStrokeColor(1, 0, 0, 1)
physics.addBody(polygon, "static")

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()

polygon.x = skeleton.x + bone.worldX
polygon.y = skeleton.y + bone.worldY
polygon.rotation = bone.worldRotation
polygon.xScale = bone.worldScaleX
polygon.yScale = bone.worldScaleY
end)

The idea is to pose the skeleton with the animation which modifies the bones' local transform (x/y/rotaton/scalex/scaley), updateWorldTransform so the bones' world transform is computed, then update the polygon's transform.

Corona docs say, "vertices: An array of x and y coordinates. These coordinates will automatically be re-centered about the center of the polygon." This is suboptimal documentation. I guess the polygon position is the polygon's centroid. You could compute the centroid (you can use my code here) so you know the distance from where Spine wants the origin (0,0) of the vertices (which is at the bone position) and where Corona puts the origin (the Corona polygon position). You'll probably need to use Corona's setReferencePoint so the polygon uses the bone position as the origin. If you don't then, for example, when the bone rotates the polygon will rotate around its centroid when what you want is for it to rotate around the bone.

Hopefully this helps a little.

Hi Nate,

Thanks a lot for reviewing my question, it helped me a lot, I'm almost there, check how my physics bounding box looks so far:

Image removed due to the lack of support for HTTPS. | Show Anyway

I just want the bounding box to draw a display object where to put physics on for the bounding box, so even if the drawn display polygon doesn't look well positioned due to the reference point (I can always make the display object invisible), the physics polygon drawn by the Corona's display.newPolygon() function is almost good enough, I just need to flip the body horizontally from what I can see, but not sure how.

Here is how I drew the physics polygon passing a table with the bounding box/bone's vertices

local torso = skeleton:findBone("torso")
local vertices = skeleton:getAttachment ("bb-torso", "bb-torso").vertices

local polygon = display.newPolygon(skeleton.group, 0, 0, vertices)
polygon:setFillColor(0, 0, 1, 1)
polygon.strokeWidth = 1
polygon:setStrokeColor(1, 0, 0, 1)
physics.addBody(polygon, "static", {shape=vertices})

And here is how I' have updated the Runtime function based on your suggestion:

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()

--- Update bounding box's position polygon.x = -skeleton.x - torso.worldX polygon.y = -skeleton.y - torso.worldY polygon.rotation = -torso.worldRotation polygon.xScale = torso.worldScaleX polygon.yScale = -torso.worldScaleY
end)

Any idea how can I finalize to position the physics polygon for the bounding box on the torso?

Thanks in advance
Hector

Looks neat! I'm not sure what you are asking though?

Thx Nate! Bounding box is backwards on the horizontal axis (right side of the box should be on the left), so I just wanted to see if you had any idea how to turned it in the correct orientation. I think it has to do with the order the vertices get drawn, so let me keep trying to put them in the correct order.

Regards
Hector

Not sure why that would be, sorry. Careful it isn't a coincidence that it shows up almost correctly. Maybe test with a few different bounding boxes.

3 anos depois

Hi Nate, Hector for your posts, and any others who can help,

Firstly I hope adding onto this thread helps

I supported and bought spine in the first kickstarter, cos it looked awesome, so i have to say well done to the esoteric
team on creating and building on it. Second i use corona sdk as my coding environment, i was new to
game coding and corona has helped me learn alot. I realise theres other platforms but for now corona works for me.

I have been wanting to use spine to create in game animations, but i have been creating games with
physics simulation. As a result i have struggled to integrate the two. With the advent of bounding boxes
and some better lua support for meshes and other features i wanted to have another go at using spine in my game
animation.

I am sure i am not alone in corona sdk land.

Would you or your team please be able to take some time out of your busy schedule to help answer some of my questions
I am happy to post a few links back in the corona forums to spread your solutions if that helps too.

Use cases involving spine boy using box2d physics bodies and spine animation.

Use case 1: Walking
How can i use spine animation to move bounding box physics objects based on spine animation?

Use case 2:
If the skeleton falls i want to disable any spine animation, remove the joints, or runtime enter frame event restrictions, so that the skeleton breaks apart and the body parts/part breaks off and tumbles using physics.

Use case 3:
Can this skeleton react to collisions from other objects eg a cannon ball and topple over.

Use case 4:
Can we make the object a ragdoll, by applying joints, and have the spine skeleton joints react to physics. If so,
how do we find the correctly bone attachment points? Can we restrict joint mobility movement, eg cant bend an elbow backwards?

how do i traverse the pine skeleton to create these joints, eg ensuring i am
connecting the skeleton bones correctly and that they are aligned correctly (to prevent spine and box2D conflicting)?

heres the corona reference for joints if needed.
https://docs.coronalabs.com/guide/physics/physicsJoints/index.html#pivot local pivotJoint =
physics.newJoint( "pivot", bodyA, bodyB, anchor_x, anchor_y ) what would be the method to create a
joint using bones

Posts that i have been reading that see to to provide soem good fodder are: but no solution yet.

corona
[Corona] Help to position bounding box on a bone
Corona SDK: Example on using atlas and Bounding box
[Corona]How to make a bone follow a physics bounding Box
Performance issue in corona SDK

other
BB position like in SPINE


good code - cant quite get it to work
Box2D Controlled Character Movement
Make Spine character's parts follow box2d Bodies

Also heres my code attempt and resulting inverted and mis-scaled bounding boxes. image included as well.

Its my understanding that the errors might possibly have to do with my worldtransform calculations, or a difference in y axis sign between spine and corona.

I would really appreciate your, and anybody elses, assistance to get me over this conceptual hurdle i (an most likely others) face.

Thanks
Kadlugan aka Nick

PS As i understand the lua runtime is going through a revamp as we speak, feel free to comment how or if this has an effect.



---

 This example shows simple usage of displaying a skeleton with queued animations.
local spine = require "spine-corona.spine"
local physics = require "physics"

physics.setDrawMode( 
               
--- "normal" ) "hybrid" )
--- "debug" ) physics.start( true ); physics.setGravity( 0, 10 ) local rootDir = "examples/myExamples/spineboyPhysics/" local json = spine.SkeletonJson.new() json.scale = 0.4 --- so it fits on screen local skeletonData = json:readSkeletonDataFile(rootDir .. "spineboy.json") local skeleton = spine.Skeleton.new(skeletonData) --- local sprites = spine.GetAtlasSprites( "examples/myExamples/spineboyPhysics/spineboy.atlas" ) local sprites = spine.GetAtlasSprites( rootDir .. "spineboy.atlas" ) sprites.ATLAS_HELPER_setup(skeleton) skeleton.group.x = display.contentWidth * 0.5 --- skeleton.group.y = display.contentHeight * 0.9 skeleton.group.y = display.contentHeight * 0.5 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", "run", 0.2) --- AnimationState has a queue of animations and can apply them with crossfading. local state = spine.AnimationState.new(stateData) --- state:setAnimationByName(0, "test") state:setAnimationByName(0, "walk", true) --- state:addAnimationByName(0, "jump", false, 3) --- state:addAnimationByName(0, "run", 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 --- bounds:update(skeleton, true) local bbPolygons = {} local worldVertices = {} for i, bb in ipairs(bounds.boundingBoxes) do local bbName = bb.name local boneName = string.sub(bb.name, 4) --- name format eg "torso" from "bb-torso"
--- I would prefer a more direct way of finding attachment to slot to bone reference
--- Is there one? print(bbName, boneName) local bone = skeleton:findBone(boneName) local attachment = skeleton:getAttachment (bbName, bbName)
--- local attachment = bone:getLoadedAttachment() --- is this function possible, to avoid name format fudge above
--- or can i get it frome a slot search.
--- what is the best way local vertices = attachment.vertices
--- where do i use this.
--- attachment:computeWorldVertices (skeleton.x, skeleton.y, bone, worldVertices) local polygon = display.newPolygon(skeleton.group, 0, 0, vertices) polygon:setFillColor(1, 0, 0, 1) polygon.strokeWidth = 1 polygon:setStrokeColor(1, 0, 0, 1)
--- to make it easier to access the various elements later?? or is there a better way polygon.attachment = attachment polygon.bone = bone polygon.vertices = vertices --- Do i need to manipulate these vertices to flip their
--- y position
--- add the physics body physics.addBody(polygon, "static", {shape=vertices})
table.insert(bbPolygons, polygon)
end local lastTime = 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()
--- update the bounding box polygons for i, polygon in ipairs(bbPolygons) do
--- polygon.attachment:computeWorldVertices (skeleton.x, skeleton.y, polygon.bone, worldVertices)
--- is this needed each frame?? Can i use it to fix my problems with orientations?
--- Update the bounding boxes position polygon.x = skeleton.x + polygon.bone.worldX polygon.y = skeleton.y + polygon.bone.worldY polygon.rotation = polygon.bone.worldRotation polygon.xScale = polygon.bone.worldScaleX polygon.yScale = polygon.bone.worldScaleY end end)

This is quite a complex topic to cover briefly. As such I don't have a good answer for you at the moment. The new Lua runtime will be pretty much as close to the old runtime on the API level as possible. I have not yet started work on the Corona specific parts.

My plan is to actually write tutorials for the use cases you mentioned once I'm done updating all the runtimes to the latest and greatest. I'm afraid I can't give an ETA on this. Let me try to briefly answer the use cases. I'm sorry that this might not be super helpful.

Use case 1: You can attach bounding boxes directly in Spine (which I assume you already know), then get their world position at runtime. You want to use the SkeletonBounds "class" and call SkeletonBounds.update(yourSkeleton, true). This will update the vertices of all bounding box attachments and should be in the correct coordinate system. You just need to add that to your EnterFrame listener and should get what you need.

Use case 2: Simply don't call AnimationState.update|apply/Skeleton.updateWorldTransform then set the worldX/worldY and a/b/c/d entries of each bone to what the physics engine gives you. Use Bone:rotateWorld to set the rotation, and simply set worldX/worldY.

Use case 3: This is very involved, especially if you want to keep playing back a skeleton animation. I don't have a good answer for this at the moment.

Use case 4: This is essentially like use case 2 if I understood correctly. For joint constraints, you'll have to use the facilities provided by Corona's physics engine. Spine doesn't have any special support for that.

Thanks BadLogic/Mario

Really appreciate your quick reply to say that your on the case. Right now thats ok to say that things are a work in progress. What i am pleased to hear is that you've got the same intent as I do for spine in my game ideas. I'll try some of the tips you suggested and post back with any success I have. Keep up the good work.

PS Ive been looking in on the spine-lua fork of the runtime you are working on. Sorry i probably cant provide much assistance, other than what Ive read elsewhere. eg

  1. the optimisations suggested here (in waffle link) to improve the speed of lua processing. ie localisation of functions and metatable use. You seem to be doing this is the latest revamp
    https://waffle.io/EsotericSoftware/spine-runtimes/cards/577150b93c67531e0011c5de

  2. The ability to directly and efficiently reference the bounding box to a bone more directly and vice versa to allow more obvious referencing. Pardon my ignorance if i'm looking at this the wrong way. Even though i have been reviewing the code, Im really not completely across how best to access the functions efficiently. I was thinking that given the tree nature of the skeleton, that having a few more handles to move between attachments and bones might be sensible. Slots appear to be able to access their parent bone, but attachments can't(?) access their parent slot, and in turn bone.

Without a find bone function using 'ipairs'. It seems like you have might have had a reason and tried to separate the skin from bones to keep them at arms length?

Could this be improved with a slot field in the attachment class? Eg:



---

 BoundingBoxAttachment.lua:

local BoundingBoxAttachment = {}
function BoundingBoxAttachment.new (name, slot)
   
--- ... local self = { name = name, type = AttachmentType.boundingbox, vertices = {}, slot = slot --- or bone = bone < --- does adding this help then access back to the slot, and bone }
--- ... etc --- Slot.lua: local Slot = {} function Slot.new (slotData, bone)
--- ... local self = { data = slotData, bone = bone, r = 1, g = 1, b = 1, a = 1, attachment = nil, attachmentTime = 0, attachmentVertices = nil, attachmentVerticesCount = 0 }
--- ... etc --- Spineboy.lua: --- from my previously posted code. Seems like you for i, bb in ipairs(bounds.boundingBoxes) do local bbName = bb.name local boneName = string.sub(bb.name, 4) --- name format eg "torso" from "bb-torso" --- easy to mess up this syntax method local bone = skeleton:findBone(boneName) local attachment = skeleton:getAttachment (bbName, bbName) local vertices = attachment.vertices
--- use these variables to then create polygons --- verses with the few mods allow: for i, bb in ipairs(bounds.boundingBoxes) do local bbSlot = bb.slot local bbBone = bb.slot.bone --- or bb:getBone --- essentially chase the references back local bbAttachment = bbBone: getLoadedAttachment() --- or bb.bone.attachment local vertices = bb.vertices
--- use these variables to then create polygons

As I said, not sure if this really is a sensible way of approaching the problem. Or whether this makes things messy when you start modifying skins and attachments on the fly. eg adding new weapons or clothes to character, or loosing limbs etc.

  1. Checking that the error statements in some procedures. I seem to quite often hard fail with errors, and don't get nice
    eg in Skin.lua has a few
function self:getAttachment (slotIndex, name)
   if not name then error("name cannot be nil.", 2) end
             if not slotIndex then error("slotindex cannot be nil.", 2) end    

---

 Add this
             ...

function self:addAttachment (slotIndex, name, attachment)
   if not name then error("name cannot be nil.", 2) end
             if not slotIndex then error("slotindex cannot be nil.", 2) end    

---

 Add this
             if not attachment then error("attachment cannot be nil.", 2) end    

---

 Add this
   ...
end

 .. etc

Sorry i'm adding this here rather than a bug request, or pull request. Just an observation.

Anyway, I realise your far more across the object model than I am, and that some of my ideas are likely born from ignorance. However I hope writing them down at least makes them part of the discussion for others following this thread. Thanks for your time. If any of this is worth discussion let me know, but don't let it take you away from the actual task at hand of the Runtimes updates and tutorials.

BTW Ive added the zip attachment with my .lua .spine and .atlas file, in case that allows you to speed up examples. ie have draw some bounding boxes on spineboy. etc Feel free to use or not.

  1. Yeah, I try to revamp this across the board.
  2. We curently try to keep the runtimes in sync with the reference runtime for libGDX/Java. Such a change would require the blessing of Nate. We'll see 🙂

Thanks for the code. Once I get to the tutorials on physics integration I'll likely rip some of it!

22 dias depois

Gotcha, No Probs. 🙂


Congrats on the update BadLogic. Thanks for all your efforts. :clap: The examples look great, and great to have the mesh features working so well.

I noticed that you had a comma missing (but fixed it a couple of days ago) in SkeletonJson ln 566. I tried doing a pull request to let you know but i didnt have permissions and my fork was way behind making it difficult - i am not a power user of git by any means.

Anyway, I have attached a full bounding box model of spineboy to save you some time with building the physics examples. my last attached zip only had the head body and legs. Im not sure if how i have added them to the bones as separate slots is how you need but hope they help. I have tried to use a common naming convention of adding "bb-" to the bone name.

Looking forward to the physics examples. cheers 🙂

That's awesome! I'm still in update mode as we made some massive (and awesome) changes to AnimationState. Will ping you here once I commence working on the physics tutorial.

2 meses depois

Roger that. Thanks


PING


Howdy badlogic, how goes the physics demo you mentioned? I can see you've been pretty active on the forums, so i am guessing various things are on your plate. Any chance of a quick very rough example to get things started before xmas? thx

Sorry, very unlikely to happen before xmas. I'm finishing up our new UE4 plugin and then have to port the latest 3.6.0-beta changes 🙁

2 meses depois

Ok, thanks Badlogic. Hope the new plugin / 3.6.0 goes well. I will work on other things in the meantime. Have a good xmas and look forward to the examples in the new year. cheers


Hey Badlogic, now that we are into the new year, i just wanted to check how your going on the examples.
cheers Nick

Soon 🙂

2 meses depois

ok. thx 🙂


Hey Badlogic,
A couple of months have passed since i last touched base. Any progress on a demonstration of spine use with physics (corona sdk, others).

If its still far off, perhaps if you can provide a simple single example, then perhaps the community can build on that. Might make building an example easier. I assume those examples i provided with bounding boxes are enough for a ragdoll, or basic jump example?

cheers
Nick

Hey. I'm sorry for the repeated delay on this. We are in a constant resource struggle to work on the runtimes themselves versus auxiliary things like examples, e.g. physics integration.

I'll try to come up with a simple sample (minus an accompanying tutorial text) next week based on your example code. I've opened an issue here [corona] Provide physics integration example · #892

Thanks Badlogic, Sounds like a good plan. :clap: