Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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:

enter image description here

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.

share|improve this question
    
I'm not sure about this particular system, but can't you just turn off kinematics for the "ghost" and move/rotate it manually? –  Tetrad Dec 20 '11 at 23:46
    
Wouldn't that also disable collisions on the ghost? Maybe ghost wasn't the best analogy for it - perhaps a clone. –  David Gouveia Dec 21 '11 at 0:11
    
I.e. collisions with the clone should affect the main body as well (in the exact same way). Would your suggestion work in that case? –  David Gouveia Dec 21 '11 at 0:40
    
Beats me, probably not. –  Tetrad Dec 21 '11 at 1:11

2 Answers 2

up vote 5 down vote accepted

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:

  1. 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.
    
  2. Attach each holder to the "mainHolder" using a WeldJoint. This will prevent them from moving away from one another. The FixedRotation on the mainHolder prevents them from rotating. I don't know if there's a bug in farseer but if you add a WeldJoint and both bodies have FixedRotation == 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);
    
  3. Attach your "object" bodies to their respective holders using RevoluteJoints. 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);
    
  4. 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:Example image of test bodies.

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.

share|improve this answer
    
It helped perfectly, thanks a lot! –  David Gouveia Jan 5 '12 at 15:40
    
It seems there is still one missing piece of the puzzle missing. How to instantly relocate the entire system to another position in the world. I need to have this to "wrap" the objects around the screen borders. Just setting the position on the main holder is not working. –  David Gouveia Jan 5 '12 at 16:54
    
Nevermind the previous question, it seems to work if relocate all holders and main bodies at the same time. –  David Gouveia Jan 5 '12 at 17:03
    
Glad to help and, yes, you'd need to relocate all bodies. You could build it into a class and store the relative positions to the main body (Vector2 difference between the body position and the main body). Then reposition the main one and just update their positions relative to the main one. –  Richard Marskell - Drackir Jan 5 '12 at 18:07
    
That's pretty much what I did. :) –  David Gouveia Jan 5 '12 at 18:08

Unfortunately I cannot check this answer since i'm on a phone right now, so apologies if it doesn't work as I expect.

I think you could use several existing joints to achieve what you want. Create a body with no collision geometry at the corner of your triangle, you can then use three distance joints to achieve the translation you want. Then if you connect the two collidable bodies together with a fixed angle joint they will rotate together.

share|improve this answer
    
I'm also a bit short on time at the moment, and will give it a try tonight. But although my example only had two bodies, I will actually need something more complex than this, with 9 connected bodies instead. Does your idea still apply? –  David Gouveia Dec 21 '11 at 9:23
    
@David: That looks... interesting. Can you say more about what you're trying to achieve with this setup? I wonder if there might not be some alternative way to achieve what you want. –  Ilmari Karonen Dec 21 '11 at 12:05
    
@IlmariKaronen There's a link at the end of my question to another question describing exactly what I'm trying to achieve. Basically I'm trying to handle physics correctly in a 2D environment where bodies can "wrap" around the borders, and appear on several sides of the screen simultaneously. –  David Gouveia Dec 21 '11 at 19:12
    
@Martin I still won't have time to test this today, so I'll report back again tomorrow. –  David Gouveia Dec 21 '11 at 19:12
    
Okay, I've tried this now but couldn't get it the work. The problem is that I want to prevent the whole system from rotating. The 3 distance joints (which can be replaced by 2 weld joints too) keeps the system rigid but does not prevent it from rotating. –  David Gouveia Dec 22 '11 at 14:11

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.