When it comes to handling physics in 2D games, few libraries come with the pedigree of Box2D. For implementing piles of rigid bodies behaving realistically in collisions, it is an ideal tool. On the other hand, when implementing character movement in a platforming game like Super Mario Bros, it can take quite a bit of tweaking to get the behavior to feel right.
That being said, it is certainly possible to setup Box2D bodies in such a way to create a high-quality platforming experience. Here’s a description of the setup that’s been working for me so far.
Before I go into the body solution I use for my platforming character, I should explain the sort of level I intend to navigate. In addition to rectangular platforms that the player can traverse by jumping, I want to be able to handle inclines that the player can walk up and down. You can see a screenshot below of one of my testing environments.
With that platforming environment in mind, let’s talk about defining the character’s body. One of the easiest Box2D shapes to define is a simple rectangle which is actually pretty suitable for most situations in a platformer. However, the simple box solution doesn’t work for me because of the inclined ground. The corners of a rectangle will generally catch on the inclines, preventing the character from moving forward as expected. To remedy this, I use a rectangle with clipped corners like the one below. The clipped corners allow the block to easily slide up and down inclines as I push it around the level to simulate walking.
The second crucial ingredient for the character body is a second smaller body attached to the bottom of the main body. I set this rectangle up as a Box2D sensor (a body that senses collisions, but doesn’t cause or react to them) that will tell me when my character is on the ground. This sensor will let me know when I should transition my character to and from a falling state.
The standard approach when using Box2D sensors is to implement a contact listener to inform the program of when the sensor has begun or ended contact. I found however that, at least in the the XNA port of Box2D, the order of the contact callbacks can get confused when the foot sensor hits inclined ground so I ended up polling the sensor every frame to set my character’s grounding flag.
Now with my physics body defined, it’s time to actually start moving it around. There are two major components to a platforming character’s movement: horizontal movement by walking/running and vertical movement by jumping.
Jumping is easy enough to implement by applying a vertical impulse on the player’s body when the jump button is pressed. This pushes the character up into the air with a good sense of degrading acceleration as the world’s gravity brings them back to earth. Using just a single impulse for jumps however results in all jumps being the same height regardless of how long the player pressed the jump button. In order to allow more jump height control, I degrade vertical acceleration (reduce it by 25% every tick for example) as long as the jump button is not being held. This way, the player can get the full height of the original jump impulse by holding down the jump button while also being able to get short hops from quick button taps.
While applying impulses works well for jumping, the initial delay required to overcome inertia is not suitable for character movement on the ground. Players expect their characters to be able to turn on a dime. In order to accomplish this, I directly set the x-coordinate of the character’s linear velocity according to player input.
With the basic movement control implemented, the final step is to implement one of the physically impossible standards of platforming games: air-control, the ability to move and even change direction in mid-air. On the most basic level, I accomplish this by directly setting the x-velocity of the character in mid-air just as I would while the character is on the ground (being careful not to overwrite my y-velocity in the process.) One unfortunate side-effect of this approach is that it now becomes very easy for the character to become stuck on the sides of platforms by pushing into them. To avoid this, I implemented a bit of logic to disable air-control when the character body (not the foot sensor) collides with a platform. I then re-enable air-control once the body is free of collisions. This allows the player to maneuver freely in the air without getting stuck on platforms.
And there you have it. While it does takes some work, implementing platformer controls in Box2D is quite do-able. So, if you want to make your own platformer, just grab Box2D and jump to it!