Box2D How to rotate wheel around axis by pulling one of its edges?

378 Views Asked by At

I am new to Box2D (JBox2d in this case) and I am creating a wheel menu on an Android app. I want to allow the user to select one menu item and the wheel should rotate automatically to the wanted section. The wheel body is dynamic, attached by a revolute joint at its center to an anchor (static) I am using a distance joint between the user tap location within my wheel and a static body located on top of my wheel. A click on the section named TA_Multilist

My problem is with the settings of the joint. I can't figure out the combination of length/damping/frequency so I can have a fast pull with minimum oscillation at the end. Also, if I pick one of the elements on the upper side of the weel, they stop at the right place. But if I tap one at the end, the joint doesn't respect the length of 0 I gave it and I end up with this : Offsetted wheel

If I use a length of 0, and dampingRatio of 1 and a frequencyHz of 0, the result is perfect but I have no animation : It goes instantaneously to the right position.

On iOS I did the same menu using UIKit Dynamics and I had a great result : https://www.dropbox.com/s/mb2i44geinw9yp6/iOS_wheel_rotation.mov?dl=0

Thanks in advance for any guidance.

1

There are 1 best solutions below

3
On BEST ANSWER

I think the basic problem is with the type of the joint you're trying to use.

Distance Joint assumes that the distance between two connected points is constant (the basic assumptions of box2d joints in general, can bend this rule a bit, but still...).

Try using MouseJoint and just remember:

  • When you're creating the MouseJoint and attaching it to the body (so exactly when you're creating MouseJointDef), you specify a target which in this specific moment (AND ONLY THEN) means the part of the body in which you want to anchor the MouseJoint (pointing out once again - it's within this body!). So in your case this target should be indicating the touched part of your wheel.

  • When you're done with creating of the joint (so after you had called <World_Object>.createJoint(<your_joint>)) the target indicates the place you would like the previously set target(within this body) to be moved to (so this anchor at the top of the wheel).

So basically you should create your mouse joint on touch with code similar to this:

MouseJoint wheelJoint;
MouseJointDef mouseJointDef = new MouseJointDef();
mouseJointDef.bodyA = <something>;
mouseJointDef.bodyB = wheelBody;
mouseJointDef.target.set(0 + chosenWheelPositionOffsetX, 0 + chosenWheelPositionOffsetY);
mouseJointDef.target.addLocal(wheelCenterX, wheelCenterY);
mouseJointDef.dampingRatio = <chosen_value>;
mouseJointDef.frequencyHz = <chosen_value>;
mouseJointDef.maxForce = <chosen_value>;
wheelJoint = (MouseJoint) mWorld.createJoint(mouseJointDef);

and after that you should call

wheelJoint.setTarget(topAnchorX, topAnchorY);

Tweak <chosen_value>s so they make your view work exactly as intended.

I hope it's all clear, let me know if something isn't. Also just pls let me know if changing the joint type helps with your issues.