Tutorial: Physics in a 2D platformer game
What is a platformer game without a character to control? Exactly. That's why we are now going to add the player into the game.
Adding the player and gravity
For our physics implementation we will ignore the actual trapezoid shape of the player and only use its bounding box. Because we might want to add other objects to our game that are affected by physics in the same way as the player (think of enemies) all physics related code goes into an abstract class dedicated to handling gravity and world collisions. We'll call this class PhysicsObject. The PhysicsObject class will be a subclass of the BBox class we created earlier.
abstract class PhysicsObject : BBox { private readonly int GRAVITY = 300; public virtual void Update(GameTime gameTime) { position.Y += (float)(GRAVITY * gameTime.ElapsedGameTime.TotalSeconds); } }
In this example, the effect of gravity is an instantaneous constant force pulling our physics object down. Unlike real world gravity, it's not an accelerating force. You might want to implement a more complex gravity system at a later point, but for simplicity sake, we'll stick to this very basic concept of gravity for now. Gravity is expressed in pixels per second here. In this case this means that gravity causes our physics object to fall down at a rate of 300 pixels per second. You can play around with this by increasing or decreasing the value of the GRAVITY variable.
In the Update method we update the simulation for this object. It's called once every frame and takes a GameTime object as argument, which is MonoGame's way of tracking time. The gameTime variable will tell us how many seconds have passed since the last time Update was called, so we can update the position of our object accordingly.
Now is a good time to add a Player class to our game, which is a subclass of PhysicsObject. The Player class will have some code to draw our player sprite to the screen, which is up to the reader to implement. Once this is done, our player character does little more than just fall down.
Controlling the player
The player falling down is not much, but it's a start. To spice things up, we'll add a little movement code to our Player class which will allow us to move to the left or right. To do this, we'll add an implementation of Update to the Player class as well.
class Player : PhysicsObject { private readonly int MOVE_SPEED = 250; public override void Update(GameTime gameTime) { KeyboardState state = KeyboardState.GetState(); if (state.IsKeyDown(Keys.Left)) { position.X -= (float)(MOVE_SPEED * gameTime.ElapsedGameTime.TotalSeconds); } if (state.IsKeyDown(Keys.Right)) { position.X += (float)(MOVE_SPEED * gameTime.ElapsedGameTime.TotalSeconds); } base.update(gameTime); } }
At the top of the class, we've defined the speed at which the player can move. The Update method updates the player's position based on whether or not the left or right arrow keys are pressed. The base.update(gameTime) line is the C# syntax to call the Update implementation in the superclass (PhysicsObject in this case).
Wow, look at it go! So, the groundwork has been laid down. We have a world, know which bits are solid and which aren't, we have a player which is affected by gravity and we can move it left and right. Time to make it bump into things!