Click here to Skip to main content
15,881,248 members
Articles / Game Development
Tip/Trick

C# Simple 2D Game Physics (Gravity, Jumping, Movement & Block Collision)

Rate me:
Please Sign up or sign in to vote.
4.39/5 (12 votes)
28 Feb 2015CPOL3 min read 113.3K   6.5K   22   4
How I made my 2D Game, a Mario platformer type of game. I searched around the internet for most of these things, but had trouble finding it. Especially collision detection that I ended up creating a simple solution by myself.

Introduction

This is work by a simple guy doing it for fun.

When I made my first 2D game in C#, I had some problems with adding new blocks also getting working collision physics so the player wouldn't fall through the block or get stuck.

That's when I searched around the cyberweb for some pointers, or any working code that I could learn from. But I never found any that isn't using the XNA framework. I find XNA pretty aids to work with.

So I made my own, a simple collision detection that I would like to explain for others like myself.

Here's an image of the game I made.

Explanation of the game

You're Mario, going against 2 Goombas following you and falling bombs as well as that Rockets are fired at you from the sides. (Not shown in the image however)

There's 2 platforms, 1 Pipe (doesn't let you go through it :P)
Whilst everything is happening, your goal is to collect as many coins as possible (falling from the sky randomly) and staying alive as long as possible.

Keyboard Input

The keyboard input, where I move the character with Arrow keys (or (WASD) were used with the forms KeyDown/KeyUp event.

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Left:
                    Player_Left = true;
                    break;
                case Keys.Right:
                    Player_Right = true;
                    break;
            }
        }

Just an example how I did mine, as you can read there's a switch on which keypress is made and from there it does something depending on the key.

If I press left arrow key, it changes my "Move player Left" variable to true.

Gravity

For Gravity in this game, I was using a Timer that moves the character up and down depending on the following variables.

C#
int Force
int Gravity
Boolean Player_Jump

Here's how the Space keyDown is set up:

C#
if (!Player_Jump && !InAirNoCollision(pb_Player))
                        {
                            Force = Gravity;
                            Player_Jump = true;
                        }

What this says is that, if the Player is not already jumping and the player is NOT in the air as well as NOT colliding with any block (also checks so the player is within the worldframe).

My physics in this game works in the way that if there is any value in Force, the player is moved upwards (unless head is colliding with a block).

If the Force is down at 0, the player starts falling.

I made this with 2 timers (Can be done with 1, I like to sort them aside however).

Here's how I did the falling code:

C#
private void timer_Gravity_Tick(object sender, EventArgs e)
        {
            if (!Player_Jump && pb_Player.Location.Y + 
        pb_Player.Height < WorldFrame.Height - 2 && !Collision_Top(pb_Player))
            {
                pb_Player.Top += Speed_Fall;
            }

if (!Player_Jump && pb_Player.Location.Y + pb_Player.Height > WorldFrame.Height - 1)
            {
                pb_Player.Top--;
            }
        }

And this is the jumping code:

C#
private void timer_Jump_Tick(object sender, EventArgs e)
      {
          if (Force > 0)
          {
              if (Collision_Bottom(pb_Player))
              {
                  Force = 0;
              }
              else
              {
                  Force--;
                  pb_Player.Top -= Speed_Jump;
              }
          }
          else
          {
              Player_Jump = false;
          }
      }

Movement

Like in my example in the Keyboard input section, I use the following code to start moving:

C#
private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Left:
                    Player_Left = true;
                    break;
                case Keys.Right:
                    Player_Right = true;
                    break;
            }
        } 

A Boolean for Player_Left, Player_Right

I also have a timer that moves the character depending on whether the Boolean is true or not.

C#
if (Player_Right && pb_Player.Right <= WorldFrame.Width - 3 && !Collision_Left(pb_Player))
                { 
                    pb_Player.Left += Speed_Movement;
                }
                if (Player_Left && pb_Player.Location.X >= 3 && !Collision_Right(pb_Player))
                { 
                    pb_Player.Left -= Speed_Movement;
                }
            }
            else
            { 
                Player_Right = false;
                Player_Left = false;
            }

This is just an example of how I use the code, like the Speed_movement is just an Int set to in my case 3.

Block Collision

In my code, I'm using PictureBoxes as the Player as well as WorldObjects.

In this example, let's just have the following variables:

C#
PictureBox Player

PictureBox WorldObjects Block_1

I use 4 Boolean functions, to check if the Player is intersecting with the blocks sides, but to achieve this, I had to create some temporary rectangle on each side of the Block.

For example, top collision:

C#
PictureBox temp1 = new PictureBox();
temp1.Bounds = Block_1.Bounds;
temp1.SetBounds(temp1.Location.X, temp1.Location.Y - 1, temp1.Width, 1);
  • Line #1 What this does is that it creates a new picturebox
  • Line #2 Copies the bounds (The size of the source block, this case Block_1)
  • Line #3 Sets the new bounds, at the same X axis, but 1 point above Block_1 and just as wide as Block_1

See "Using the code" section for the entire code, or download the source and try it out yourself.

Using the Code

This is the InAirNoCollision code as well as all the 4 Collision functions:

public Boolean InAirNoCollision(PictureBox tar)
        {
            if (!OutsideWorldFrame(tar))
            {
                foreach (PictureBox Obj in WorldObjects)
                {
                    if (!tar.Bounds.IntersectsWith(Obj.Bounds))
                    {
                        if (tar.Location.Y < WorldFrame.Width)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }


public Boolean Collision_Top(PictureBox tar)
        {
            foreach (PictureBox ob in WorldObjects)
            {
                if (ob != null)
                {
                    PictureBox temp1 = new PictureBox();
                    temp1.Bounds = ob.Bounds;
                    temp1.SetBounds(temp1.Location.X - 3, temp1.Location.Y - 1, temp1.Width + 6, 1);
                    if (tar.Bounds.IntersectsWith(temp1.Bounds))
                        return true;
                }
            }
            return false;
        }

public Boolean Collision_Bottom(PictureBox tar)
        {
            foreach (PictureBox ob in WorldObjects)
            {
                if (ob != null)
                {
                    PictureBox temp1 = new PictureBox();
                    temp1.Bounds = ob.Bounds;
                    temp1.SetBounds(temp1.Location.X, temp1.Location.Y + temp1.Height, temp1.Width, 1);
                    if (tar.Bounds.IntersectsWith(temp1.Bounds))
                        return true;
                }
            }
            return false;
        }

        public Boolean Collision_Left(PictureBox tar)
        {
            foreach (PictureBox ob in WorldObjects)
            {
                if (ob != null)
                {
                    PictureBox temp1 = new PictureBox();
                    temp1.Bounds = ob.Bounds;
                    temp1.SetBounds(temp1.Location.X - 1, temp1.Location.Y + 1, 1, temp1.Height - 1);
                    if (tar.Bounds.IntersectsWith(temp1.Bounds))
                        return true;
                }
            }
            return false;
        }
        public Boolean Collision_Right(PictureBox tar)
        {
            foreach (PictureBox ob in WorldObjects)
            {
                if (ob != null)
                {
                    PictureBox temp1 = new PictureBox();
                    temp1.Bounds = ob.Bounds;
                    temp1.SetBounds(temp1.Location.X + temp1.Width, temp1.Location.Y + 1, 1, temp2.Height - 1);
                    if (tar.Bounds.IntersectsWith(temp2.Bounds))
                        return true;
                }
            }
            return false;
        } 

I've uploaded a .zip file containing an executable file, resource files (all the images), and a full documented source code.

If you have any questions, feel free to email me at robert@hydeen.se.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Help desk / Support
Sweden Sweden
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Suggestiontutorial Pin
Gemmimah Sabida29-May-22 21:28
Gemmimah Sabida29-May-22 21:28 
GeneralThank you sir Pin
asiaFearson31-Jan-17 12:50
asiaFearson31-Jan-17 12:50 
GeneralMy vote of 3 Pin
Isaac RF2-Mar-15 23:34
professionalIsaac RF2-Mar-15 23:34 
QuestionNIce work, thanks for sharing Pin
DumpsterJuice2-Mar-15 8:12
DumpsterJuice2-Mar-15 8:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.