- Edited
Corona touch listeners on parts of a spine animation
I have a question about detecting touches on various parts of the skeleton in the Corona Runtime. I have seen this post in the forum: [Corona/lua] get attachment/slot for click/touch events. I understand that it's no longer trivial for performance reasons to add a touch listener in Corona directly to an attachment to a slot. So I've tried adding display objects on top of the skeleton (as suggested in that old post), and this seems to almost work
but I can't figure out how to line the boxes up perfectly with the slots. Here's a video of what I've got so far:
https://drive.google.com/file/d/17PbDmZ_6NCdq8NU3RVTIalN0q4qzztxl/view?usp=sharing
As you can see, the boxes seem to be centered around the joint of the bone/lot
which is good
but they're not pivoting the same way the attachments do. That is to say, the arm's bounding box is centered around the cat's shoulder, instead of the middle of the arm, where it should be. Another example is the cat's body. The big box, for the cat's body, needs to be offset by half its height, so that it's perfectly over that body part. I'd like to get this right, so I can use it in gameplay, but I'm not sure how to correct it. I've tried adjusting the local y positions and anchors of my collision boxes, but to no avail. My current approach is to create the white collision boxes like this:
local slot = cat.skeleton:findSlot(name)
local w, h = slot.attachment.width, slot.attachment.height
local w, h = slot.attachment.width, slot.attachment.height
local collider = display.newRect(0,0,w, h)
cat:insert(collider)
And then just assign them positions every frame, like so:
local bone = cat.skeleton:findBone(name)
local collider = cat.boneColliderGroups[name]
collider.x = bone.worldX
collider.y = bone.worldY
collider.rotation = -bone.rotation
But there's clearly something I'm missing. Is this the preferred method for getting a touch listener on each part of the animation? Is there a code sample somewhere? I hope so!
I don't have Corona specific code that does exactly what you want, sorry! In general though, hit detection is usually done with axis aligned rectangles. Even for games where hit boxes are extremely important, like Street Fighter, they still use axis aligned bounding boxes (AABB) for all hit detection:
Image removed due to the lack of support for HTTPS. | Show Anyway
Given that, I wince every time I see people trying to be more precise than necessary, especially when they want to do pixel perfect hit detection or use meshes (or all the attachments!) for hit detection. While you can do that, or use bounding boxes for hit detection, you are likely better off getting the location of a bone and doing point-circle detection or point-rectangle detection. We can help with that if you are interested.
That said, your code looks OK, except what is the origin for rotation? Probably it uses the center of the rectangle but to make it rotate as the bone does, the origin should be the bone position. You probably want to look at anchorX
and anchorY
:
https://docs.coronalabs.com/api/type/DisplayObject/anchorX.html
Long ago the spine-corona runtime worked by using display.newImage
and positioning those scene graph objects based on the bone transforms. You may be able to glean some useful code from that:
https://github.com/EsotericSoftware/spine-runtimes/blob/6b7ed29684bf0ae49a337a1d758a0b2b91ee2d98/spine-corona/spine-corona/spine.lua
It sets the anchor to 0.5,0.5
, which seems to be the default. So it's positioning the attachment at the attachment's position relative to the bone, then rotating it around it's center. Maybe you can get this to work for your scene graph objects, but I'd still suggest using a bone position and point-circle or point-rectangle detection.
Another thread on this topic was just posted, you might check it out:
More precise Bounding Box?
I am using bounding box from Spine editor. It binds to the slot and moves with it.
In Corona, you can get it with:
your_bb = your_skeleton.getVertices("boneName", "slotName", "attachmentName")
Then you can create a physical body from it and bind it to the you display object:
physics.addBody( your_display_object, "dynamic", { shape = your_bb, bounce = 1, friction = 1 })
Thanks for everybody's kind replies!
@Nate Thanks for the advice
I think using big blob colliders is what I want. The origin for rotation is the problem, and I had been playing with the anchors with little success. That historical link about the display.newImage stuff is useful, and helped me understand the way that meshes are constructed now, for speed. I'll keep playing with it, but I doubt that AABB will be very useful. Nice sf4 reference, by the way! I'm more of a Cody player myself, though.
@kostus Thanks for the advice! I'll check out getVertices. Sounds like it should do the trick!