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

12 Responses to “Farseer physics 3.3.1 and XNA: Platformer character”

  1. Yannick says:

    Thanks a lot and happy birthday a little bit late !

  2. Johnny says:

    Nice Tut!!! but TimeInterval Jumping system seems to be buggy for me, because I want Collision system method. Could you provide some helpful link? Thank you.
    I use:
    OnCollison += myfuc;
    bool myfuc(Fixture fixtureA, Fixture fixtureB, Contact contact)
    {
    islanding = true
    return true;
    }

    but it’s not stable, it works occasionally.

  3. What is it exactly that you want to do? :)

  4. ArknoiD says:

    Thanks bro! You really helped me alot !

  5. Nico says:

    Hey, great tut, but how would you use only one texture to the whole character? thanks!

  6. Just draw a single rectangle at a location offset to the center of mass of the creature, filled with a texture over the entire thing. The visualization can be totally independent of the physics. I demonstrate it like this here because that makes it easier to see what is going on.

  7. […] credit where credit is due – a lot of my code is based on Farseer Samples and this post by Roy […]

  8. Thanks, that is cool too hear!

  9. Richard says:

    Hi Roy

    First of all, thank you for your hard work!
    I really would love to use this tutorial, but unfortunately Farseer changed some things in V. 3.5.
    Because I am really a beginner on this topic and I can’t find something like a changelog, I would really appreciate if you can tell me how to get this to work.

    I’m not sure, but it seams like the only problem is the “CreateFixedAngleJoint”, which doesn’t exist anymore. I hoped that “FixuedRotation” on the Body will compensate, but now my character isn’t moving at all.

    Thanks for your help!
    Cheers,
    Richard

  10. Hey Richard,

    I haven’t touched farseer in a while, but maybe you can just set the angle of your body yourself every frame, or does that cause stuttering?

Leave a Reply