Preview

Part 2 Part 3

A physics engine, like Farseer, is a piece of technology that allows you to simulate real-world-physics inside your game. It enables you to incorporate elements like gravity, weight, collision detection/response and much more into your game without having to rediscover and implement the laws of physics yourself.

Farseer is one of the most used physics engine for 2D games in C# and XNA, it’s tries to mimic the functionality of the popular Box2D physics engine which was built with C++ in mind. Note that you can also use Farseer if you’re not using XNA, it also has bindings for Silverlight and plain C#/.Net.

A while ago I wrote a tutorial for Farseer 2.X on how to create and manipulate a character and how to setup a few platforms and a seesaw. That tutorial still remains popular but since then a lot of things have changed in the newer versions of Farseer so I think it is useful to revisit this topic. This tutorial is the first in a series. The end result will be the same as the old platformer tutorial but we’ll get there in byte sized pieces this time and I’ll try to go a bit more in depth. Anyway, let’s get started!

Setting up Farseer and XNA

Ok so first things first, start visual studio and create a new XNA 4 Windows Game Project. You can then download the Farseer Physics Engine from here. At the time of writing the latest version was v3.3.1. Extract the archive and open the Visual Studio solution named ‘Samples XNA’. Switch to Release mode and build the project named ‘Farseer Physics XNA’. Now in the output directory (bin/x86/release) find the file ‘FarseerPhysicsXNA.dll’ and copy it to your game project. Switch back to the your own game project (you can close the other Visual Studio window). Locate the references in the solution explorer, right click it and click ‘Add Reference…’ browse to your project folder and select ‘FarseerPhysicsXNA.dll’. You can now use Farseer in your XNA project!

Setting up a simple physics simulation

Now let’s get some physics going. Open Game1.cs and add the following using statements at the top of the file.

using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;

Also add the following member to the Game1 class.

World world;

The World class is the most important class in Farseer. It represents the entire physics simulation. Every object that influences the simulation should be registered with your instance of the world class. Of course to make it work we have to instantiate it and tell it what kind of gravity we want. To do so add the following to your LoadContent() method.

world = new World(new Vector2(0, 9.8f));

As you can see I’ve chosen a gravity of 0ms^2 on the horizontal axis and 9.8ms^2 on the vertical axis. Just as on earth! The world object needs to do some work every frame to keep the simulation going so add this to your update method:

world.Step((float)gameTime.ElapsedGameTime.TotalSeconds);

Now we still wont see anything, there aren’t any objects, or bodies as they are called in Farseer, yet in our simulation. Lets remedy this situation by adding a crate. Add the following member to Game1.cs

Body body;
const float unitToPixel = 100.0f;
const float pixelToUnit = 1 / unitToPixel;

And add the following code at end of the LoadContent method

Vector2 size = new Vector2(50, 50);
body = BodyFactory.CreateRectangle(world, size.X * pixelToUnit, size.Y * pixelToUnit, 1);
body.BodyType = BodyType.Dynamic;
body.Position = new Vector2((GraphicsDevice.Viewport.Width / 2.0f) * pixelToUnit, 0);

Now as you can see we use a handy factory to create a rectangular body, we pass the world object so that it can be registered to it. However when passing the size of the body we first multiply this by the newly introduced constant pixelToUnit. Farseer uses Meters, Kilograms and Seconds as units while we are using pixels. So we need to convert all sizes and lengths to meters when we pass them to Farseer by multiplying them with pixelToUnit and, vice versa, when we get data back from Farseer, for example the position of a body, we need to convert back from meters to pixels. We use the same idea when setting the body’s position.

We also set the body type to Dynamic. This is a normal body, you also have Static, which means that it is immovable and Kinematic which means that it has no mass and some other properties (we wont use it).

Anyway add an image for the crate to your content project, I’ve named mine ‘Crate.png’. Then add the following member to Game1.cs.

Texture2D texture;

Now we can finally draw something to the screen. Add the following code to your Draw method

spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque);
Vector2 position = body.Position * unitToPixel;
Vector2 scale = new Vector2(50 / (float)texture.Width, 50 / (float)texture.Height);
spriteBatch.Draw(texture, position, null, Color.White, body.Rotation, new Vector2(texture.Width / 2.0f, texture.Height / 2.0f), scale, SpriteEffects.None, 0);
spriteBatch.End();

When you run the game now you should briefly see a crate fall to its doom before it disappears from the screen.

A more interesting simulation

Now of course this is a bit of a boring simulation to see something interesting happen we would need at least two objects, and preferably much more. Now we can duplicate the code a couple of times but I believe that you should never have to write the same code twice. Delete the following lines.

  • The line that starts with spriteBatch.Draw(…) in your Draw method
  • The members unitToPixel and pixelToUnit
  • The body member and everything that involves the body in the LoadContent method.

Now create a new class called DrawablePhysicsObject. This class will be a wrapper around a body object. We will automatically convert between pixel coordinates and the coordinates used by Farseer and we will make drawing a bit easier. Since there are no new concepts introduced in this class I’ll just place the code right here:

public class DrawablePhysicsObject
    {
        // 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 Body body;
        public Vector2 Position
        {
            get { return body.Position * unitToPixel; }
            set { body.Position = value * pixelToUnit; }
        }

        public Texture2D texture;

        private Vector2 size;
        public Vector2 Size
        {
            get { return size * unitToPixel; }
            set { size = value * pixelToUnit; }
        }

        ///The farseer simulation this object should be part of
        ///The image that will be drawn at the place of the body
        ///The size in pixels
        ///The mass in kilograms
        public DrawablePhysicsObject(World world, Texture2D texture, Vector2 size, float mass)
        {
            body = BodyFactory.CreateRectangle(world, size.X * pixelToUnit, size.Y * pixelToUnit, 1);
            body.BodyType = BodyType.Dynamic;

            this.Size = size;
            this.texture = texture;
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            Vector2 scale = new Vector2(Size.X / (float)texture.Width, Size.Y / (float)texture.Height);
            spriteBatch.Draw(texture, Position, null, Color.White, body.Rotation, new Vector2(texture.Width / 2.0f, texture.Height / 2.0f), scale, SpriteEffects.None, 0);
        }
    }
}

Now lets set this code to work! Create the following members in Game1.cs

List<DrawablePhysicsObject> crateList;
DrawablePhysicsObject floor;
KeyboardState prevKeyboardState;
Random random;

And add this line to the end of the LoadContent method.

random = new Random();

floor = new DrawablePhysicsObject(world, Content.Load("Floor"), new Vector2(GraphicsDevice.Viewport.Width, 100.0f), 1000);
            floor.Position = new Vector2(GraphicsDevice.Viewport.Width / 2.0f, GraphicsDevice.Viewport.Height - 50);
floor.body.BodyType = BodyType.Static;
crateList = new List<DrawablePhysicsObject>();
prevKeyboardState = Keyboard.GetState();

You see that we create one DrawablePhysicsObject with a Static BodyType. That’s going to be our floor. We also create a list of crates and do some keyboard logic. Lets create a method to fill that list of crates. Add this method to Game1.cs

private void SpawnCrate()
{
	DrawablePhysicsObject crate;
	crate = new DrawablePhysicsObject(world, Content.Load<Texture2D>("Crate"), new Vector2(50.0f, 50.0f), 0.1f);
	crate.Position = new Vector2(random.Next(50, GraphicsDevice.Viewport.Width - 50), 1);

	crateList.Add(crate);
}

This method will spawn a random crate somewhere at the top of the screen. We will trigger this method by a pressing the spacebar. To do so add this to the update method before base.Update().

KeyboardState keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Space) && !prevKeyboardState.IsKeyDown(Keys.Space))
{
    SpawnCrate();
}

prevKeyboardState = keyboardState;

And finally add these last few lines in between spriteBatch.Begin() and spriteBatch.End() in your draw method so that we can see what’s going on.

foreach (DrawablePhysicsObject crate in crateList)
{
    crate.Draw(spriteBatch);
}

floor.Draw(spriteBatch);

Run the simulation and start hammering on the spacebar you should see something like this: [youtube=http://www.youtube.com/watch?v=-B9OYh2f9ng]

This concludes this tutorial. In the next tutorial we will talk about springs and joints and ways to make compound bodies so that you can have more interesting simulations!

Farseer v3.3.1 XNA Tutorial 1

Thanks to Ryan Foy for pointing out some errors in the code that somehow made it onto this blog