Edit
Problem solved (see Drackir's answer). Here's a demo of what I was trying to achieve with this joint. More info about the scenario on this other question.
Problem
I'm trying to create a very specific type of joint in Farseer that behaves like this:
- Objects should always keep the same distance between them in both the X and Y axes.
- Translation - A collision with one of the objects should move the entire group together, but the group must not rotate - only the individual objects may rotate around their centers as a result of torque.
- Rotation - Objects should always have the same rotation. A collision with one of the objects should make all others rotate the exact same amount.
Here's a picture:
If there's no way to achieve this with Farseer out of the box, how would I go about extending it to create a new type of join that works like this? Basically I want every body to behave like a "clone" of the others, but with a fixed offset between them.
Answer
Ok, after about two hours of tinkering I managed to do this but it requires adding some extra bodies. You'll probably want to extract this stuff into a method/class but the basic idea is this:
Create what I call "holder" bodies for your objects. These bodies share the size and position of your "objects" but don't participate in collisions. Essentially, they are clones.
//Create "Main" (center) body
_bodyMain = BodyFactory.CreateRectangle(World, 5f, 5f, 1f);
_bodyMain.BodyType = BodyType.Dynamic;
_bodyMain.Position = new Vector2(2, 2);
//Create "MainHolder"
_bodyMainHolder = BodyFactory.CreateRectangle(World, 5f, 5f, 1f);
_bodyMainHolder.BodyType = BodyType.Dynamic;
_bodyMainHolder.CollisionCategories = Category.None; //Prevents collisions
_bodyMainHolder.Position = new Vector2(2, 2);
_bodyMainHolder.IsSensor = true;
//See http://farseerphysics.codeplex.com/discussions/222524 for why they're sensors
_bodyMainHolder.FixedRotation = true;
//Note: Only add FixedRotation for the main one, leave it off of the other
// holders. I'll explain later.Attach each holder to the "mainHolder" using a
WeldJoint
. This will prevent them from moving away from one another. TheFixedRotation
on the mainHolder prevents them from rotating. I don't know if there's a bug in farseer but if you add aWeldJoint
and both bodies haveFixedRotation == true
, the joint doesn't work properly. This is why only the main holder has.FixedRotation = true
.//Weld the holders together so they don't move. Assumes another holder is defined
// for the object on the right side (bodyRightHolder).
JointFactory.CreateWeldJoint(World, _bodyMainHolder, _bodyRightHolder,
_bodyRightHolder.Position - _bodyMainHolder.Position, Vector2.Zero);Attach your "object" bodies to their respective holders using
RevoluteJoint
s. This locks your objects to the holders but allows them to rotate freely.//Lock the actual bodies to the holders
JointFactory.CreateRevoluteJoint(World, _bodyMainHolder, _bodyMain, Vector2.Zero);
JointFactory.CreateRevoluteJoint(World, _bodyRightHolder, _bodyRight, Vector2.Zero);Make your real objects rotations match each other by attaching an angle joint. Note: you don't have to attach an angle joint to each and every pair of objects. Just add an angle joint to the main body and the other body and the rotations will translate across all objects.
//Make them rotate the same as each other
JointFactory.CreateAngleJoint(World, _bodyMain, _bodyRight);
That's it! Just add the extra code for each other object/object holder you want and it will handle the rest. Here's an image to illustrate my test:
Here you will see the green bodies are the holders. They do not rotate or collide and are welded together. The yellow and red bodies are your "objects" (yellow is the main). You can see that they are rotated by the same amount and are rotating around their respective holders. Also, only the red and yellow bodies participate in collisions. I believe this meets all three of your conditions above.
Working Example
If you load up the Farseer "Samples XNA" solution and find SimpleDemo1.cs ("Samples XNA" project > "Samples" folder), I rewrote it (code here) to test.
Hope this helps. Let me know if you have any questions.
No comments:
Post a Comment