Sgt. Conker We are "Absolutely Fine"

9Sep/106

Article: XNA Farseer Platform Physics Tutorial

by Roy Triesscheijn

Today I’m going to introduce you to a neat 2D physics engine for XNA called Farseer. With the help of this 2D physics engine we are going to create a small platform ‘game’ while introducing the important concepts of Farseer like bodies, geometry, joints and springs.

By the end of the tutorial, you'll be able to build something like:

Set-up

Before we can get started please download the latest stable release at http://farseerphysics.codeplex.com (at the time of writing that was 2.1.3) and extract the solution somewhere. Now also download the “Added motor to RevoluteJoint and FixedRevoluteJoint” patch at http://farseerphysics.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=70619. You will find two files in the archive (RevoluteJoint.cs and FixedRevoluteJoint.cs) extract these and copy these over the files in “Farseer Physics 2.1.3 XNADynamicsJoints”.

Creating a project

Now let’s fire up Visual Studio and create a new XNA 3.1 Windows Game project, call it anything you like. I’ve called it “FarseerPlatformer”. Now add the Farseer project to our solution: right click the our solution in the solution explorer and select “Add existing project”, then browse to where you’ve extracted Farseer and select the FarseerPhysicsXNA.csproj.

Now add a reference to the FarseerPhysicsXNA project in your own project by right clicking the References folder in the solution explorer and choosing “Add reference”. Then select FarseerPhysicsXNA from the tab “Projects” and press ok.

If your solution explorer now looks like the picture on the left we’re ready to try and compile. Hit F6 on your keyboard. There should be no errors.

My  first physics

The physics simulator class is the heart of the Farseer physics engine and will control all our physics objects. Let’s create one!

Open Game1.cs and add the following using statements at the top of the file.

[csharp]
using FarseerGames.FarseerPhysics;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Factories;
using FarseerGames.FarseerPhysics.Collisions;
[/csharp]

Now let’s create a PhysicsSimulator called physics. Add this definition at the top of the class.

[csharp]
PhysicsSimulator physics;
[/csharp]

And instantiate it by adding the following line to the end of the constructor.

[csharp]
physics = new PhysicsSimulator(Vector2.UnitY * 500);
[/csharp]

This will create a new physics simulator with a predefined gravity of (0, 500) which means that there is a constant force of strength 500 pushing everything down. 500 here is just an arbitrary number, play around with this value as much as possible to tweak the feel of your games.

All we need todo to make the physics simulator work is making it update every frame by adding the following line at the end of the Update method.

[csharp]
physics.Update((float)gameTime.ElapsedGameTime.TotalSeconds);
[/csharp]

So that’s it. We’re done! But well, you can’t actually see anything yet. Let’s make a very simple class called PhysicsObject. I will not put down the entire class right here, see the source code for that. However there is one method that deserves special attention:

[csharp]
protected virtual void SetupPhysics(PhysicsSimulator physics,
Vector2 position, float width, float height, float mass)
{
body = BodyFactory.Instance.CreateRectangleBody(physics,
width, height, mass);
body.Position = position;

geom = GeomFactory.Instance.CreateRectangleGeom(physics,
body, width, height);
geom.FrictionCoefficient = 0.5f;
}
[/csharp]

In this method we create the ‘physical representation’ for our new object. For this we need two fields: body of type Body and geom of type Geom. Body represents a handle which we can push and pull and apply all sorts of forces to. Geom (short for geometry) handles the actual collisions and friction. Both objects fire numerous events which you can handle, the most useful one is geom’s OnCollision event that we will use in the final chapter.

Instantiating them is very easy. Just use the apropiate factory class to get a new instances, make sure to always choose the overload that also asks for a PhysicsSimulator object so that your object is automatically registered in the simulation. Also note that the PhysicsSimulator uses the center of an object as its position, while the SpriteBatch uses the top left corner normally, take this into account when drawing by setting the origin to the center of the texture when using the SpriteBatch.
Add a texture to your content project and quickly instantiate a new PhysicsObject like this:

[csharp]
squareTex = Content.Load<Texture2D>("square");
box = new PhysicsObject(physics, new Vector2(100, 0), 64, 64, 10, squareTex);
[/csharp]

Then add the following lines to the draw method in Game1.

[csharp]
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate,
SaveStateMode.SaveState);
box.Draw(spriteBatch);
spriteBatch.End();
[/csharp]

If you run the simulation now you should see a falling square. Nifty isn’t it?

Laying grounds

Now we need to make some ground that will stop our square from falling down at terminal velocity. To do this we’re going to make a static body. This means that the body is unaffected by all forces but still is in our simulation, handy for making immovable objects like ground and walls. To do this neatly we will make a new class that inherits from the PhysicsObject class. Call this class StaticPhysicsObject.
Because of inheritance all we have to write in this new clas is this:

[csharp]
public class StaticPhysicsObject : PhysicsObject
{
public StaticPhysicsObject(PhysicsSimulator physics, Vector2 position, float width, float height, Texture2D texture)
: base(physics, position, width, height, 1, texture)
{
body.IsStatic = true;
}
}
[/csharp]

Note how we always pass a mass of 1, mass isn’t important for a static object.

Create a new field StaticPhysicsObject ground in Game1 and instantiate it in LoadContent like this:

[csharp]
ground = new StaticPhysicsObject(physics, new Vector2(GraphicsDevice.Viewport.Width / 2, 500), GraphicsDevice.Viewport.Width, 64, squareTex);
[/csharp]

Don’t forget to draw it in the Draw method.

You should now see a square falling down and stopping when it hits our new ground.

Joints

Let’s make the simulation a bit more interesting by creating a see-saw. Quickly add two more PhysicsObjects, instantiate them like this:

[csharp]
seeSawBottom = new PhysicsObject(physics, new Vector2(175, 300), 50, 50, 1000, squareTex);
seeSawTop = new PhysicsObject(physics, new Vector2(175, 200), 300, 30, 25, squareTex);
[/csharp]

And write some draw code. Now let’s fire up the simulation again. You will now see our original block smash hard into our see-saw, rolling out of screen while the see-saw almost falls apart.

This looks awesome, however we would like the see-saw to behave as one object, so let’s introduce a joint. A joint is a way of fixing two bodies or a body and the background together (like an axel that connects a wheel to a car). There are multiple types of joints. For an explantion of the different types of joints see this page: http://www.farseergames.com/storage/farseerphysics/Manual2.1.htm#_Toc213068491

We are going to create a revolute joint, that fixes two bodies together but still alows them to rotate independently, very handy for a see-saw or a wheel. To demonstate this we will create a new class called CompositePhysicsObject as below:

[csharp]
public class CompositePhysicsObject
{
public CompositePhysicsObject(PhysicsSimulator physics, PhysicsObject poA, PhysicsObject poB, Vector2 relativeJointPosition)
{
this.poA = poA;
this.poB = poB;

joint = JointFactory.Instance.CreateRevoluteJoint(physics, poA.body, poB.body, poA.Position + relativeJointPosition);
poA.geom.IgnoreCollisionWith(poB.geom);
poB.geom.IgnoreCollisionWith(poA.geom);
}

public virtual void Draw(SpriteBatch spriteBatch)
{
poA.Draw(spriteBatch);
poB.Draw(spriteBatch);
}

protected RevoluteJoint joint;
protected PhysicsObject poA;
protected PhysicsObject poB;
}
[/csharp]

Just as with the bodies and geoms we create a joint with a factory. Creating a revolute joint is very easy, the second body is attached to the first body at the absolute (world) position. To make it easier to create a composite physics object we are using a relative position (or offset) from the first body. Note that you will have to make sure yourself that the bodies overlap, the second body will not be moved by creating a joint. (Note: bodies don’t have to overlap to be fixed together by joints, but this will look pretty funny).

We also need to make sure that the geometries of both physics objects do not register colliding with each other; else we would get some very buggy results.

Let’s go back to the Game1 class, add a field called seeSaw of type CompositePhysicsObject and change the load content method to look like this:

[csharp]
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
squareTex = Content.Load<Texture2D>("square");
box = new PhysicsObject(physics, new Vector2(100, 0), 64, 64, 10, squareTex);
seeSawBottom = new PhysicsObject(physics, new Vector2(175, 300), 50, 50, 1000, squareTex);
seeSawTop = new PhysicsObject(physics, new Vector2(175, 285), 300, 30, 25, squareTex);
seeSaw = new CompositePhysicsObject(physics, seeSawTop, seeSawBottom, new Vector2(0, 15));
ground = new StaticPhysicsObject(physics, new Vector2(GraphicsDevice.Viewport.Width / 2, 500), GraphicsDevice.Viewport.Width, 64, squareTex);
}
[/csharp]

Also update the drawing method:

[csharp]
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
box.Draw(spriteBatch);
seeSaw.Draw(spriteBatch);
ground.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
[/csharp]

Run, you will now have a box dropping on a fully functional see-saw.

Springs

You know what would be even cooler? If our see-saw would have a spring that would make our see-saw come back up again after our falling box hits it. With Farseer you can make numerous types of springs, for a full overview see the Springs section in the manual here: http://www.farseergames.com/storage/farseerphysics/Manual2.1.htm#_Toc213068498

To improve our see-saw we are going to use an AngleSpring. This type of spring tries to keep two objects (or one object and the background) at a specified angle by applying a specified amount of torque (or less).

Let’s create a new class that inherits from our CompositePhysicsObject class. I couldn’t think of a decent name for it, so I just called it SpringPhysicsObject. This new class will compose two physics objects together (just as before) but will now also add an angle spring to try and keep two objects at a specified angle. (If you want to force two objects to always stay at a specified angle of each other you should use an angle joint, and if you want one object to always stay at a specified angle, use a fixed angle joint).

[csharp]
public class SpringPhysicsObject : CompositePhysicsObject
{
public SpringPhysicsObject(PhysicsSimulator physics, PhysicsObject poA, PhysicsObject poB, Vector2 relativeJointPosition, float springForce, float springDampening)
: base(physics, poA, poB, relativeJointPosition)
{
angleSpring = SpringFactory.Instance.CreateAngleSpring(physics, poA.body, poB.body, springForce, springDampening);
angleSpring.MaxTorque = springForce;
}

protected AngleSpring angleSpring;
}
[/csharp]

As you can see we again don’t need to write a lot of code since inheriting from CompositePhysicsObject will already join our two bodies together. All we need to do is to create a new angle spring, as always via a factory. I think spring force and spring dampening speak for themselves. MaxTorque is the maximum amount of torque that will be applied to stay at the given angle. Note that you usually need very high values for spring force to make this work properly (just as in real life).
Now that we have this new SpringPhysicsObject, replace our CompositePhysicsObject and instantiate it like this in the LoadContent method.

[csharp]
seeSaw2 = new SpringPhysicsObject(physics, seeSawTop, seeSawBottom, new Vector2(0, 15), 10000000, 10000);
[/csharp]

Also update the draw method.
Now run the simulation and see how our see-saw behaves now!

Force

Now what if we want to control the falling box? Maybe make it move a little, have it jump up and down, etc.
To do this we need to apply force to our object. To demonstrate this we’re going to make a new class called Character that inherits from PhysicsObject.

[csharp]
public class Character : PhysicsObject
{
public Character(PhysicsSimulator physics, Vector2 position, float width, float height, float mass, Texture2D texture)
: base(physics, position, width, height, mass, texture)
{
}

public virtual void Update(GameTime gameTime)
{
HandleInput(gameTime);
}

protected virtual void HandleInput(GameTime gameTime)
{
keyState = Keyboard.GetState();

//Apply force in the arrow key direction
Vector2 force = Vector2.Zero;
if (keyState.IsKeyDown(Keys.Left))
{
force.X -= forcePower * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (keyState.IsKeyDown(Keys.Right))
{
force.X += forcePower * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (keyState.IsKeyDown(Keys.Up))
{
force.Y -= forcePower * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (keyState.IsKeyDown(Keys.Down))
{
force.Y += forcePower * (float)gameTime.ElapsedGameTime.TotalSeconds;
}

body.ApplyForce(ref force);

oldState = keyState;
}

public float forcePower;
protected KeyboardState keyState;
protected KeyboardState oldState;

}
[/csharp]

As you can see force is easily applied just by constructing a force vector and calling body.ApplyForce(). We pass the vector by reference so that the garbage collector doesn’t have to jump in and act too often (since Vector2 is a value type, its normally copied each time it’s passed to a different method, don’t worry too much about that right now).
You can apply impulse in the same way. (Impulse is direct, useful for jumping and explosions, while force is steadily added, more useful to make a jetpack work for example).
Let’s play: in Game1 replace our box of type PhysicsObject with a box of type Character. Set box.forcePower to 1000000. Also add box.Update(gameTime); to the Update method in Game1 and make sure the box is being drawn.
If you did everything correct you should now be able to control the falling box with the arrows on your keyboard.

A game character

Now we’ve got all of the basics covered it’s time to talk about creating a more realistic game character. Without physics you would move an object by changing its position when a key is pressed. Jumping would be done by creating two ‘fake forces’ that sent the object up and down. When using a physics engine you shouldn’t just move your character, this will make it very hard for Farseer to handle collisions because for Farseer it looks like the character just teleported a tiny amount (there are no forces, impulses or torque present). For a realistic character we need to apply forces to a body, however this causes a problem: how much force do we apply? Do we keep applying forces (e.g. the character keeps accelerating)? This sounds very unrealistic, as a normal person quickly accelerates in just a few steps and then stays at his running speed. We could do with impulses, that instantly generate movement, however stopping the character is going to be even more problematic then. And if we encounter a slope or if the friction is not set to 0 the character will slow down until the user releases and presses the move key again.
Suffice it to say that I’ve been trying all sorts of stuff for two days to get a character moving the way I want it (instant start and stop, controllable air movements, steady running speed, also characters normally don’t fall over).
Luckily I came across Bryan Dismas’ blog who wrote an article on this http://amazingretardo.simiansoftwerks.com/2010/02/17/platformer-character-control-farseer-physics-engine/. He adopted this idea from Robert Dodd (http://boxycraft.wordpress.com) and I’m going to change it even further.

Boxboy
Image by Robert Dodd

The idea is to create a character from two parts: the upper body is just a simple rectangle. The lower body is a circle/wheel that we rotate so that we can move around and climb slopes without problems. We’re going to create a slightly simpler version of this.

  • Upper body: a rectangle body always kept up-right using a fixed angle joint.
  • Lower body: a circle connected to the upper body using a revolute joint.

With the current version of Farseer this is enough to have a nice character jumping around. So let’s write some code.
Create a class called CompositeCharacter which inherits from Character.
The class is fairly long because I also had to add a bit of state management to make walking, jumping and moving in-air work. However for this tutorial the most important is the overloaded method SetupPhysics that is listed here below.

[csharp]
protected override void SetupPhysics(PhysicsSimulator physics, Vector2 position, float width, float height, float mass)
{
//Create a body that is almost the size of the entire object
//but with the bottom part cut off.
float upperBodyHeight = height - (width / 2);
body = BodyFactory.Instance.CreateRectangleBody(physics, width, upperBodyHeight, mass / 2);
//also shift it up a tiny bit to keep the new object's center correct
body.Position = position - Vector2.UnitY * (width / 4);
centerOffset = position.Y - body.Position.Y; //remember the offset from the center for drawing

//Now let's make sure our upperbody is always facing up.
fixedAngleJoint = JointFactory.Instance.CreateFixedAngleJoint(physics, body);

//Create a wheel as wide as the whole object
wheelBody = BodyFactory.Instance.CreateCircleBody(physics, width / 2, mass / 2);
//And position its center at the bottom of the upper body
wheelBody.Position = body.Position + Vector2.UnitY * (upperBodyHeight / 2);

//These two bodies together are width wide and height high :)
//So let's connect them together.
motor = JointFactory.Instance.CreateRevoluteJoint(physics, body, wheelBody, wheelBody.Position);
motor.Motor_Enabled = true;
motor.Motor_MaxTorque = 1000f; //set this higher for some more juice
motor.Motor_Speed = 0;

//Create geomitries.
wheelGeom = GeomFactory.Instance.CreateCircleGeom(physics, wheelBody, width / 2, 16);
geom = GeomFactory.Instance.CreateRectangleGeom(physics, body, width, upperBodyHeight);

wheelGeom.IgnoreCollisionWith(geom);
geom.IgnoreCollisionWith(wheelGeom);

//Set the friction of the wheelGeom to float.MaxValue for fast stopping/starting
//or set it higher to make the character slip.
wheelGeom.FrictionCoefficient = float.MaxValue;
}
[/csharp]

Quite a lot is happening here, but nothing should be really new. We first create a body that is going to be the upper part of our character, we then shift its position a bit and calculate its shift from the center. (This is handy for if we want to draw our final character). A simple fixed angle joint keeps our upper body at all times.

We then create the lower body (wheelBody) which is sized like a wheel just as wide as our upper body. Its center is positioned at the bottom of the upper body (see the picture above again).

The lower body is fixed to the upper body with a revolute joint, and because we downloaded the ‘motor’ patch we can force the lower body to rotate while it stays attached to the upper body. If you think about we’ve just created a Segway actually.
Geometries are created as usual and the upper and lower bodies are told not to collide with each other.

Finally we set the friction of the lower body to the highest possible value. This way the movement of our character will be very responsive. You can lower the amount of friction for a different feel (be sure to play around a bit, 0.5f gives quite a funny feel).

Congratulations, you’re now familiar with the basics of the Farseer physics engine. Be sure to fire up the simulation and play around a bit. Maybe try to make a more complicated level with the objects you now have.

Afterthoughts

You now have a bit of a grasp on the techniques that the Farseer physics engine offers you. This engine could easily be extended to make even more fun physics objects, like moving platforms. However because this is a tutorial, some things in the code have been neglected, so if you would like to extend the tutorial code, please first make sure that you make some kind of base object, of which CompositePhysicsObject and PhysicsObject extend. Then make some sort of drawing manager, this will make your life a lot easier!
This tutorial has shown you a few useful tricks like Polymorphism (a Character is still a PhysicsObject) which saves writing a lot of duplicate code. Make sure that you use these techniques to the max they will make your life a lot easier!
I hope you’ve enjoyed this tutorial, for more of my tutorials see www.roy-t.nl.

Download sample source: FarseerPlatformer.zip (under the MS-PL License)

Comments (6) Trackbacks (10)
  1. Yeah. Nice Article.

    Has anyone gotten this to work with the new Farseer 3?

  2. how do you stop the character? I read that some use an angle joint to accomplish a smooth, non-sliding stop but I’m not sure how and where to attach the joint.

  3. I wouldn’t know about an angle joint, since the player is always kept upright. But you could pin the player to the background using a normal joint to have him stop immediately. I’ve never tried that approach though.

  4. Great article. Thanks for the sample code as well. I got this working, but ran into a few afterthoughts of my own. When the player hits a wall, the player can jump again (unintentional?). Also, there seems to be a shudder when the player moves across several tiles (all of the same height) quickly or when walking straight into a wall. Did you ever run into this? It could be something in my code becasue I adopted this onto Farseer 3.2 and had to translate a lot of it.

  5. Great article for a beginner, the only part I am having trouble with is the last! I cant find the patch for the Joints??

    Thanks still :D


Leave a comment

(required)