Farseer physics 3.3.1 and XNA: Joints

In the previous tutorial, which you can find here, we created static and dynamic bodies. In this second tutorial we are going to take a look at joints. Simply said a joint is used to make a connection between two bodies or a body and the background.  The place where a joint is attached is called the anchor. Usually a joint has two anchors. One placed on the first body and one placed on a second body or on the world itself. Farseer uses the following naming convention for this. If a joint is ‘fixed’ it provides a joint between a body and the background/world. If a joint is not fixed it is used to connect two separate bodies to each other. So a RevoluteJoint connects two bodies and a FixedRevoluteJoint connects a body and the background/world.

Overview of joints

There are quite a few types of joints in Farseer:

Standard joints

Angle joints

Keeps a body at a fixed angle from another body or the world.

Distance joints

Keeps a body at a fixed distance from another body or from an anchor in the world.

Friction joints

Applies translational and angular friction to a body.

Line joints

A line joint can best be seen as a spring. It linearly connects to bodies (or a body and the background) together and tries to keep them at a fixed distance. It does not limit relative rotations but it does limit translation over one axis. They can be a bit tricky to place since the mass of the bodies themselves already affects the distance between the two bodies so setting the ‘at rest’ state is a bit of trial and error. Note that Line Joints are a new addition to Farseer and are not available in Box2D.

Prismatic joints

Enforces that two bodies can only slide in a linear motion (one degree of freedom) with respect to each other. See http://en.wikipedia.org/wiki/Prismatic_joint

Revolute joints

The most standard joints. Allows a body to rotate around an implicit axis coming from the screen (Z-Axis). Can be used to connect a body to the background or to another body.  Can be motorized.

Slider joints

A sort of prismatic joint that doesn’t limit the bodies to just linear motion. Best described as a combination of a revolute joint and a prismatic joint. Note that Slider Joints are also not available in Box2D.

Weld joints

Connects two bodies together disallowing any form of relative rotation/translation.

More complex joints

Gear joints

Connects two revolute joints or a revolute joint and a prismatic joint. Simulates that they are connected by gears so if the body on the first revolute joint rotates the body on the second revolute joint will rotate in the opposite direction.

Pulley joints

Used to create a pulley system. (Two bodies both connected to a rope that runs over a pulley). Can be used to create sophisticated elevators.

If you would like to know more about the joints Farseer offers you can check the Box2D documentation here (Farseer is a C# implementation of Box2D, and although it’s growing slowly to become more than that the best place for documentation is still the Box2D website).

Refactoring last week’s example

After doing some coding I found that I need access to the world-to-screen and screen-to-world conversion methods for the joints and they are currently members of the DrawablePhysicsObject class. So before we start creating or own joints we must first refactor last week’s example.

Create this new helper class:

    public static class CoordinateHelper
    {
        // Because Farseer uses 1 unit = 1 meter we need to convert
        // between pixel coordinates and physics coordinates.
        // I've chosen to use the rule that 100 pixels is one meter.
        // We have to take care to convert between these two
        // coordinate-sets wherever we mix them!

        public const float unitToPixel = 100.0f;
        public const float pixelToUnit = 1 / unitToPixel;

        public static Vector2 ToScreen(Vector2 worldCoordinates)
        {
            return worldCoordinates * unitToPixel;
        }

        public static Vector2 ToWorld(Vector2 screenCoordinates)
        {
            return screenCoordinates * pixelToUnit;
        }
    }

And then update the DrawablePhysicsObject class to use the helper class.

Some setup

Last week we added a list to store all the boxes that we randomly spawn. This week we’re going to create ‘paddles’ connected by joints. To store the paddles we’re going to need another list. So open Game1.cs and add the following field:

List paddles;

Then add the following three lines to draw the paddles:

foreach (DrawablePhysicsObject paddle in paddles)
{
    paddle.Draw(spriteBatch);
}

I’ve also added another image to the content project called ‘Paddle.png’.

Adding some bodies and joints

Now to demonstrate how to use joints I’m going to create three paddles. The first paddle will just be a simple body connected with revolute joint to the background. This means that it can spin freely. The second paddle is almost the same, but it will be motorized, adding some interaction to the scene. Finally we combine two line joints to create a trampoline. After this you should have a basic understanding on how joints work in Farseer.

A simple revolute joint

Add the end of the LoadContent method initialize the list we use to store the paddles. Then after that add the following code to create the first paddle:

// Create a simple paddle which center is anchored
// in the background. It can rotate freely
DrawablePhysicsObject simplePaddle = new DrawablePhysicsObject
(
    world,
    Content.Load("Paddle"),
    new Vector2(128, 16),
    10
);

JointFactory.CreateFixedRevoluteJoint
(
    world,
    simplePaddle.body,
    CoordinateHelper.ToWorld(new Vector2(0, 0)),
    CoordinateHelper.ToWorld(new Vector2(GraphicsDevice.Viewport.Width / 2.0f - 150,
                                         GraphicsDevice.Viewport.Height - 300))
);

paddles.Add(simplePaddle);

As you can see we first create a simple body, just as in the previous tutorial. The body is 128 pixels wide and 16 pixels high (note that the constructor of the DrawablePhysicsObject converts these units to world coordinates). It has a mass of 10KG. Note that we don’t have to set the position of the body. This is implicitly done by the joint, which fixes the body on the background at the anchor positions.

Next we create the joint. The first argument is our physics simulation and is used to register our joint to the simulation. We then pass the body this joint should be applied to. Since this is a Fixed joint we don’t need to pass a second body. The joint will connect the first body to the world. We then have to give some coordinates. We pass the center of the body (0,0) and somewhere in our world. Note that we use the conversion methods to go from pixel to world coordinates. Also don’t forget the last line, where we add the paddle to our list of paddles, else it won’t show up for drawing.

You can now run the simulation. Again press space to drop crate, you will see that we’ve create a small paddle that rotates freely when hit by a crate.

A motorized joint

The motorized joint is very similar:

// Creates a motorized paddle which left side is anchored in the background
// it will rotate slowly but the motor is not set soo strong that
// it can push everything away.
DrawablePhysicsObject motorPaddle = new DrawablePhysicsObject
(
    world,
    Content.Load("Paddle"),
    new Vector2(128, 16),
    10
);

var j = JointFactory.CreateFixedRevoluteJoint
(
    world,
    motorPaddle.body,
    CoordinateHelper.ToWorld(new Vector2(-48, 0)),
    CoordinateHelper.ToWorld(new Vector2(GraphicsDevice.Viewport.Width / 2.0f,
                                         GraphicsDevice.Viewport.Height - 280))
);

// rotate 1/4 of a circle per second
j.MotorSpeed = MathHelper.PiOver2;
// have little torque (power) so it can push away a few blocks
j.MotorTorque = 3;
j.MotorEnabled = true;
j.MaxMotorTorque = 10;

paddles.Add(motorPaddle);

Again we create a body and a Fixed Revolute Joint. But this time we store the joint created by the joint factory in the variable j so that we can access the properties of the joint. The revolute joint exposes a few interesting properties. The most interesting one is to motorize it. We’ve set a motor speed of pi/2. This means that the every second the joint will rotate the connected body by pi/2 radians, or a 1/4 of a circle. We also have to set the torque to give the motor enough power to rotate the body and to keep rotating even when a few crates are blocking the paddle. We also set the max motor torque and enable the motor. Again in the last line we add the paddle to our list of paddles so that it will be drawn.

A trampoline

To create a trampoline we will use two Line Joints (a sort of springs) to connect a paddle to the ground. This way we create some sort of trampoline. Add the following code:

// Use two line joints (a sort of springs) to create a trampoline
DrawablePhysicsObject trampolinePaddle = new DrawablePhysicsObject
(
    world,
    Content.Load("Paddle"),
    new Vector2(128, 16),
    10
);

trampolinePaddle.Position = new Vector2(600, floor.Position.Y - 175);

var l = JointFactory.CreateLineJoint
(
    floor.body,
    trampolinePaddle.body,
    CoordinateHelper.ToWorld(trampolinePaddle.Position - new Vector2(64, 0)),
    Vector2.UnitY
);

l.CollideConnected = true;
l.Frequency = 2.0f;
l.DampingRatio = 0.05f;

var r = JointFactory.CreateLineJoint
(
    floor.body,
    trampolinePaddle.body,
    CoordinateHelper.ToWorld(trampolinePaddle.Position + new Vector2(64, 0)),
    Vector2.UnitY
);

r.CollideConnected = true;
r.Frequency = 2.0f;
r.DampingRatio = 0.05f;

world.AddJoint(l);
world.AddJoint(r);

paddles.Add(trampolinePaddle);

Now the creation of the body should look really familiar now. Note that this time we do have to set the position of the body. The line joint will try to keep the paddle and the ground at roughly the same position as the starting position from each other so it needs some initial position.

We create two joints, they are exactly the same, except for where they connect to the paddle. One is anchored on the left side of the paddle and one on the right side. So I will only explain the first line joint.

We start by passing the body of the first body the line joint should connect to, the floor. We then pass the body of the paddle. We tell the line joint to connect to the paddle at the given relative coordinates.  We then give the axis of freedom the line joint should offer. In our case the Y-Axis.

We also set some properties, CollideConnected  means that the paddle and the floor can collide with each other. Handy now but for a wheel inside a car you might want to keep this at the default, turned off, state. We also set a nice frequency and damping ratio. Finally we add the joints to the world. Don’t forget this step! Only Fixed joints are automatically added to the world. We also add the paddle to our list of paddles to draw.

You can now run the simulation again. Try to drop a few crates on the trampoline, you will see that it behaves quite nicely.

Conclusion

Joints in Farseer are fairly easy to use and can add a dynamicity lot to your scene. Try playing around with all different joints to get a feel from them. All joints in Farseer are created using a way similar as shown in this tutorial. In the next tutorial we will add a controllable character and create a small platformer.

11 Responses to “Farseer physics 3.3.1 and XNA: Joints”

  1. Raúl says:

    Gracias por compartir tus conocimientos.
    Me ha sido de gran ayuda este tutorial.

  2. Yannick says:

    Thanks a lot for your tutorial !
    Please continue , I can’t wait the next tutorial on Farseer !

  3. Hey Yannick,

    Thanks for your comment. Sorry that you’ve been waiting so long I’ve just been so busy! This is the last day of my exams so maybe I can find some time next to week to publish the final article.

  4. Lucas says:

    Hello, great tutorials Roy, i’m waiting for the next tutorial too. Keep this work up.

  5. Noah says:

    Hello, do you have a Source code download for this? Love the tutorials, great work!

  6. Hey Noah,

    I thought I had it attached to the article but it seems I haven’t. Don’t have time to look it up now (crazy).

  7. […] Part 1 of this tutorial Part 2 of this tutorial […]

  8. Alex says:

    The source is still seems to be absent from the article

  9. Bassam Tantawi says:

    Could you please edit this article and add the source code?

Leave a Reply