Farseer physics 3.3.1 and XNA: Platformer character

It took a while, but here I finaly present you the third and final part of the Farseer Physics 3.3.1 and XNA tutorial series!

Part 1 of this tutorial
Part 2 of this tutorial

In the last two tutorials I’ve told you how to set up Farseer with XNA and how bodies and joints work. We’re going to use the techniques from these tutorials to create a character for a platformer game, think Mario or Kirby or whatever your favorite platformer character is! It’s not too obvious how to create a character in Farseer. Just applying forces to a rectangular body works OK, but traveling slopes becomes really tricky in this case and the ability to stop moving instantly becomes even more hacky (usually done by pinning the character to the background with a joint). Because of that I will use a technique described by Bryan Dismas and Robert Dodd where we create a character by combining a motorized wheel and a rectangular with an axis joint and fixed angle joint (see the previous tutorial) to create a character.

Platformer character composition

Platformer character composition

So let’s start off. First things first. I made some small changes to the DrawablePhysicsObjects class to allow circular bodies. I also found a bug in the drawing (which only happens with circular bodies). So let’s add the following constructor to the DrawablePhysicsObjects class:

/// <summary>
/// Creates a circular drawable physics object
/// </summary>
/// <param name="world">The farseer simulation this object should be part of</param>
/// <param name="texture">The image that will be drawn at the place of the body</param>
/// <param name="diameter"> The diameter in pixels</param>
/// <param name="mass">The mass in kilograms</param>
public DrawablePhysicsObject(World world, Texture2D texture, float diameter, float mass)
{
    size = new Vector2(diameter, diameter);
    Body = BodyFactory.CreateCircle(world, (diameter / 2.0f) * CoordinateHelper.pixelToUnit, 1);

    Body.BodyType = BodyType.Dynamic;

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

And to fix the drawing code replace the draw method in the DrawablePhysicsObject class with this one

public void Draw(SpriteBatch spriteBatch)
{            
	Rectangle destination = new Rectangle
	(
		(int)Position.X,
		(int)Position.Y,
		(int)Size.X,
		(int)Size.Y
	);

	spriteBatch.Draw(texture, destination, null, Color.White, Body.Rotation, new Vector2(texture.Width / 2.0f, texture.Height / 2.0f), SpriteEffects.None, 0);
}

Now we can start with the player character. Add a new class to your project called Player and add the following private fields and constructor

private DrawablePhysicsObject torso;
private DrawablePhysicsObject wheel;
private RevoluteJoint axis;

public Player(World world, Texture2D torsoTexture, Texture2D wheelTexture, Vector2 size, float mass, Vector2 startPosition)

As you can see the player is a composition of two DrawablePhysicsObjects: a torso and a wheel as mentioned above. The constructor is fairly standard, we need a texture for the torso and wheel. We need a size for the player, a mass and a start position. Let’s start implementing these details!

First, because the player is a composition, we need to calculate the sizes of the wheel and torso. We want the wheel to be just as wide as the player and to form the lower part of the body (note that this technique won’t work for characters that are wider than they are high!)

Vector2 torsoSize = new Vector2(size.X, size.Y - size.X / 2.0f);
float wheelSize = size.X;

// Create the torso
torso = new DrawablePhysicsObject(world, torsoTexture, torsoSize, mass / 2.0f);
torso.Position = startPosition;            
			
// Create the feet of the body
wheel = new DrawablePhysicsObject(world, wheelTexture, wheelSize, mass / 2.0f);
wheel.Position = torso.Position + new Vector2(0, torsoSize.Y / 2.0f);

Now we can start adding joints. We will use a Fixed Angle Joint to keep the torso straight up at all times and we use a Revolute Joint to move the wheel (feet) of the character.

// Create a joint to keep the torso upright
JointFactory.CreateFixedAngleJoint(world, torso.Body);

// Connect the feet to the torso
axis = JointFactory.CreateRevoluteJoint(world, torso.Body, wheel.Body, Vector2.Zero);
axis.CollideConnected = false;
            
axis.MotorEnabled = true;
axis.MotorSpeed = 0;
axis.MotorTorque = 3;
axis.MaxMotorTorque = 10;

Let’s also implement a draw function, which is extremely simple because we can use the drawing facilities of the two DrawablePhysicsObjects. Note that in a real game you would just draw one animated sprite over the entire player but for this tutorial this will suffice.

public void Draw(SpriteBatch spriteBatch)
{
	torso.Draw(spriteBatch);
	wheel.Draw(spriteBatch);
}

Great! Let’s go to game class, add a field for the player, load it, and make it visible!

public class Game1
{
	...
	
	Player player;
	
	...
	
	protected override void LoadContent()
	{
		...
		
		player = new Player
            (
                world,
                Content.Load<Texture2D>("Player"),
                Content.Load<Texture2D>("Wheel"),
                new Vector2(20, 75),
                100,
                new Vector2(430, 0)
            );     		
	}
	
	...
	
	protected override void Draw(GameTime gameTime)
	{
		...
		
		player.Draw(spriteBatch);
		
		...
	}
}

Ok. Run your game. If everything went well you will see your player character fall from the sky, land, and be pushed away by one of the paddles we added in the previous tutorial. You can see a body and a wheel and that they are connected. You will notice that the character keeps sliding a lot before it stands still when it’s pushed by the paddle. Based on your game this might be desirable or undesirable. You can control this behavior using the friction of the wheel. I don’t want the character to slide so much so I’ve added a bit of friction to the wheel by adding the following line in the constructor of player.

wheel.Body.Friction = 0.8f;

Higher values will stop the character from sliding at all.

Now to make the scene more interesting we will have to be able to control the player. Let’s first add movement and then later add jumping as well. Create the following enum:

public enum Movement
{
    Left,
    Right,
    Stop
}

Add the following code to your player class:

float speed = 3.0f;

...

public void Move(Movement movement)
{
	switch(movement)
	{
		case Movement.Left:
			axis.MotorSpeed = -MathHelper.TwoPi * speed;
			break;

		case Movement.Right:
			axis.MotorSpeed = MathHelper.TwoPi * speed;
			break;

		case Movement.Stop:                    
			axis.MotorSpeed = 0;
			break;
	}
}

Then go to the update function of your game class and add the following lines:

Run the game again. You should now be able to control your character. Remember that you can still press space to make some boxes fall from the sky, push them around a bit. Depending on how high you’ve set the friction of your wheel body and (max) torque of your revolute joint you might be able to push none, one or quite a few more!

Now the finishing touch is obviously jumping, and with just adding a bit of force we can get there. Add the following fields and method to the Player class:

private DateTime previousJump = DateTime.Now;   // time at which we previously jumped
private const float jumpInterval = 1.0f;        // in seconds
private Vector2 jumpForce = new Vector2(0, -1); // applied force when jumping

public void Jump()
{
	if ((DateTime.Now - previousJump).TotalSeconds >= jumpInterval)
	{
		torso.Body.ApplyLinearImpulse(ref jumpForce);
		previousJump = DateTime.Now;
	}
}

As you can see we do some management to keep track of when we last jumped. The jumping itself is done by adding impulse to the torso body and since the wheel is connected to the torso body we don’t need to do anything else. Simple right? Let’s hook this jump function up to the left control key by adding these last few lines to the Update function of your game class.

if (keyboardState.IsKeyDown(Keys.LeftControl) && !prevKeyboardState.IsKeyDown(Keys.LeftControl))
{
    player.Jump();
}

Et voila! We have a controllable player character which you can use in your very own platform game! Fire up your game and if you followed my instructions this is what you should end up with:

You can download the complete source code (includes everything from the previous two tutorials and this one) here

Fun trivia

  • I published (and wrote most) of this tutorial on my birthday, 25 now, yay!
  • In 2010 I got 2nd place on SgtConker’s Absolutely Fine tutorial contest writhing the Farseer 2.x version of this series
02
Jan 2013
COMMENTS 12 Comments

Farseer physics 3.3.1 and XNA

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 0m*s^2 on the horizontal axis and 9.8m*s^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:

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!

You can download the source code for this tutorial here: 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

19
Aug 2012
COMMENTS 13 Comments

XNA Farseer platformer physics tutorial

My XNA Farseer platformer physics tutorial is up and online at MadGameDev.com

Below is a sneak preview, but follow the above link for the complete article.

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:

Update 11-09-2012: links fixed

10
Sep 2010
COMMENTS 2 Comments

Tutorial: Using the XNA Content Pipeline for localization: Part 1, Strings

Lately I’ve been working on making localization easier. I came up with an idea to use the content pipeline and content manager to automatically localize your strings*, textures and sounds (and any other content type you might want to localize).

In part one we create a new content pipeline extension and a new content manager without much effort. And we start to replace our strings with calls to our new content manager (that replaces the default one). In the end you will be able to load a string using Content.Load<String>(“Package.Key”); The correct string will be loaded from our xnb files (imported using a custom xml importer) in the language set in the content manager.

In part two we are going to extend this example to load other content as normal (Content.Load<Texture2D>(@”Folder\Name”);). And if you’ve created a localized version this will be loaded instead of the original file.

Part 1 is now up at SgtConker.Com: http://www.sgtconker.com/2010/01/article-using-xna-content-pipeline-extensions-for-localization/

Feel free to post any comments and questions either here or at sgtconker.com.

Part 2 will probably be up end of next week.

kick it on GameDevKicks.com