- Edited
Changing bone position in libgdx
Hi, i know there has been a few posts related to this but I haven't been able to find a straight forward answer. I'm trying to create a ragdoll effect in my game when my character dies. So far I have managed to create box2d bodies matching the bounding boxes from my skeleton. This is easily done with body.setTransform(bone.getWorldX(), bone.getWorldY()....etc.)
However, when my character dies I want the physics to take over and manually change the bone position according to where the box2d body is. But as far as I understand you can only change the bones local coordinates, and I only have access the box2d body coordinates (ie the bones world coordinates). Does anyone know how i calculate the bones local coordinates from this information so that i can update my skeleton according to the box2d bodies position? Thank you!
For position, see Bone#worldToLocal
. For rotation, desired world rotation - bone.parent.worldRotation = local rotation.
Thank you..But what do you mean with Bone#worldToLocal..i can't find this method or field.
Thank you Nate! Turns out I had an old version of spine which didn't have the wordToLocal method..I got it now..However, I still can't get it to work..The rotation seems to work fine but the positions of the bones are weird and keep moving around even when the physical bodies are still. I think it might have something to do with that I don't call updateWorldTransform in the correct way. Or do i have to take the parent bone into consideration when changing the bones local coordinates? Perhaps you can take a look at the code:
// update ragdoll to correspond to boneposition..
// this part works fine
if(!dead){
for(int i = 0; i < ragDoll.length; i++){
Bone bone = bones[i];
ragDoll[i].setTransform(getX() + getWidth() / 2 + bone.getWorldX(),getY()
+ bone.getWorldY(), MathUtils.degreesToRadians * bone.getWorldRotation());
}
}
// when bird is dead update bones from ragdoll body positions
// only the rotation seems to work here
else{
for(int i = 0; i < ragDoll.length; i++){
ragDoll[i].setActive(true);
// get bones world position
float x = ragDoll[i].getPosition().x - getX() - getWidth() / 2;
float y = ragDoll[i].getPosition().y - getY();
Vector2 worldPos = new Vector2(x,y);
Vector2 localPos = bones[i].worldToLocal(worldPos);
bones[i].setX(localPos.x);
bones[i].setY(localPos.y);
bones[i].setRotation(bones[i].getParent().getWorldRotation() * MathUtils.radiansToDegrees);
bones[i].updateWorldTransform();
}
}
Use bones[i].getParent().worldToLocal(...)
, since a bone is positioned in it's parent's space, not it's local space. Note the root bone has no parent.
Use something like (assuming ragdoll rotation is radians):
bones[i].setRotation(ragDoll[i].getRotation() - bones[i].getParent().getWorldRotation() * MathUtils.radiansToDegrees);
Get it working for a single bone before trying to get ragdoll to work.
You probably want to adjust bones from the root down the hierarchy.
Thank you so much for the help, I will try that and get back to you with the result!
Worked perfect! Thank you again. I just changed Vector2 localPos = bones.worldToLocal(worldPos);
to Vector2 localPos = bones.getParent().worldToLocal(worldPos);
And it now works for the whole rag doll! Didn't have to change the rotation or account for that the root bone has no parent..not sure why, but as long as it works I'm happy
I was a bit quick to celebrate it turns out.. I didn't test the rotation properly..I got it working now though..If anyone is interested I changed the last two lines from:
bones[i].setRotation(bones[i].getParent().getWorldRotation() * MathUtils.radiansToDegrees);
bones[i].updateWorldTransform();
to:
bones[i].setRotation(ragDoll[i].getAngle() * MathUtils.radiansToDegrees - bones[i].getParent().getWorldRotation() );
skeleton.updateWorldTransform();
And now it seems to work for the whole ragdoll.
Cheers!
Hi again, I now ran into some troubles when I turn my character and flip the skeleton
The bounding boxes of the skeleton seems to be unchanged after the flip..
I read this post which seems to be about the same thing:
and concluded that the best way to go about it is to construct two ragdolls, one for each direction the skeleton is facing and to use the correct one.
To do this I tried to go through the vertices of the bounding boxes and inverting the x-coordinate when the skeleton is flipped as suggested by the post above:
BoundingBoxAttachment b = (BoundingBoxAttachment) itr.next();
float[] vertices = b.getVertices();
for(int p = 0; p < vertices.length; p+=2){
vertices[p] = -vertices[p];
}
// create box2d body from vertices
However this doesn't work and my box2d bodys are all messed up..Any ideas on how to get this to work?
It should work...
I got it working now. I don't full understand how bone rotation and position works which makes it a little difficult. Anyway, i inverted the x-coordinate of the bounding box vertices for the left facing rag doll. What I changed in order to get it to work was to also invert the bones world rotation when placing the box2D body for the left facing rag doll. Now everything works and I'm happy Thanks for the help, really appreciate it!