Pong Using Visual C#

by michael.andrews2104 in Circuits > Software

1014 Views, 3 Favorites, 0 Comments

Pong Using Visual C#

Pongscreen.png

Purpose: This is my submission for the 2021-2022 Butwin Elias Award by the Adam Iseman Foundation. My Submission this year focuses on Pong using Visual C#. My goal this year is not simply to recreate a classic video game, but to provide a guide for others who decide to get into coding, specifically those who take Computer Programming at our school. This guide is meant to showcase the various functions I have learned this year taking the course, and compile it so others make look and recreate this project, and hopefully build upon it. To reinvent the wheel, you must first understand what makes the wheel spin.

Supplies

1. A computer

2. Microsoft Visual C# 2010 Express program

3. A loud clackity clickity keyboard that makes a lot of noise so you feel like a proper programmer. (This, while beneficial, is not strictly necessary)

4. Patience. This point I cannot stress enough. You will spend, countless hours bug fixing, just to find out you put a greater than or equal to sign (>=) instead of a less than or equal to sign (<=) This is simply par for the course.

5. A desire to make something.

STEM Application

3STEM-FINAL_Web.png

The way this project relates to STEM is primarily through its technological aspect, but also in an mathematics and engineering scope. It took time to execute and design this project, going through three different iterations before settling on this one for its simplistic layout and ease of play. Mathematics also took a key role in this project's creation given the different timers and variables, and with the way the ball bounces off the paddle.

To the same regard, this project relates to STEM, but not just STEM Education, but the school I call my own. This project was made with the intentions of being a guide for students besides myself, so they may learn coding and build on my creations. My goal in all of this, will be to create something that goes beyond me, and is able to let others truly encompass what STEM is, as a teaching tool, and as my family. So lets get started.

Starting Your Project

Step1.png
Step2.png
Step3.png

Your first step for this project is to download Microsoft Visual C# 2010 Express. It is a free program and you should be able to easily find a download online for it.

After you download the program, load it up! You should be greeted by a start page.

Next, you'll want to start a new project, by clicking New Project, found just above Recent Projects.

In doing so, another screen will pop up. Click the button labeled Windows Form Application.

If everything went smoothly, you should be greeted by a screen with a white square labeled Form1.

Resizing Your Form

Step4.png
Step5.png

Now, while Pong itself is quite antique at this point, we did in fact develop bigger monitors over the years, so lets use that extra real-estate.

In the bottom right corner, you should see a menu labeled properties, and while scrolling through it, you'll find a property called Size. The default is a measly 300 by 300, That is a bit small, so lets size it up. Click on the property and change it to 1300 by 500 (1300, 500).

Sprucing Up the Place

Step6.png
Step7.png
Step8.png
Step9.png
Step10.png
Step11.png
Step12.png
Step13.png
Step14.png
Step15.png

Now, while I enjoy staring at a white rectangle as much as the next guy, its not exactly Pong. So lets add some pizazz.

First, lets start working on the top and bottom boundaries. To the left of the screen, you'll find your toolbox. Inside, instead of your typical Stanley 25' tape measure and miscellaneous nuts and bolts, you will find such things as Labels, Picture Boxes, Buttons, and so on and so forth.

For now, we will be sticking primarily to Picture Boxes. Double click the button labeled PictureBox and it should drop one in your form.

Now, one thing to keep in mind is organization, especially with Names. Names, act as the addresses inside the code. While you may be able to keep track of 100 picture boxes inside your head, I cannot. So lets rename it.

For ease of use, we call Picture Boxes "pb" and then whatever their purpose is. For instance, the top picture box acting as a boundary will be called "pbtop".

Next, we'll want to bring the picture box all the way across the form. Inside the properties menu you will see a property labeled Size. The default is (100,50), but we will want to change that to (1283, 10). While the form is (1300, 500) it has margins that must be taken into account, that is why it is 1283 instead of being 1300. Keep in mind, those numbers are the equivalent to coordinate points, and are based off the top left of the picture boxes.

You will also want to make sure the location of the picture box stays at (0, 0).

Finally, you will want to change the color of the picture box. You will want to click on the property labeled "BackColor" and you will then be greeted by another menu with a bunch of beautiful colors such as ActiveBorder and AppWorkspace. Now, these are not actual colors, you can find those within the submenus labeled "Custom" and "Web", these colors are just named this way because that is how they are used within C#. For this project, I decided to go with AppWorkspace, also known as gray.

There you have it, a gray bar across the top of your form. Isn't coding exciting?

Another Bar

Step15.png
Step16.png
Step17.png
Step18.png
Step19.png
Step20.png

Now. while you could in fact go through the steps of making another picture box, resizing it, and giving it a new splash of paint, we have copy and paste for a reason. While having the picture box highlighted, click Ctrl+C on your keyboard, and then Ctrl+V. This should cause a second picture box to appear!

Remember to rename that magically appearing bar to pbbottom.

The default location for this bar should be right in the middle, right where we do not want it. So lets change it from (0, 221) to (0,446).

And there we go! You have your top and bottom boundaries set! Lets work on the Center Divider and the ball.

Center Divider

Step21.png
Step23.png
Step22.png
Step24.png

Again, let us just copy and paste the top picture box, rename it pbcenter, as it will be going in the center, change the Size to (10, 456) and the location to (631, 0). Looking pretty good so far!

Pong Ball, While Not Actually Being a Ball.

Step25.png
Step27.png
Step26.png
Step28.png

Now, while the astute amongst you would like to point out that our ball, is not in fact, a circular shape, and is instead, a square, the reason for that is because at this point in the course, we have not been taught other shapes besides rectangles, as in picture boxes, and with this project, I would like to keep it within the boundaries of what we have been taught. Now, onto our ball.

Again, as in the previous steps, copy and paste one of the bars, rename it to "pbball", set the Size to (30, 30) and the Location to (621, 208). The end result after all previous steps, should be a sideways H with a square in the center.

Left Paddle

Step29.png
Step31.png
Step30.png
Step32.png

One of the difficulties I had while coding this project would be that of how to make the ball bounce at various angles, depending on where it hit the paddle. My solution, would be to make multiple paddles! This line of reasoning will make more sense once we get to actually typing out code.

Copy and paste the ball picture box once more, name it "pbleftuser1", set the size to (10, 30) and the location to (100, 149). Now, as you may have noticed, there is an extra 1 at the end of that name. That is because each paddle, is actually made up of 5 picture boxes, labeled 1 through 5.

Copy and paste four more of those tiny rectangles, and set them as such:

  • pbleftuser2
    • Size (10, 30)
    • Location (100, 178)
  • pbleftuser3
    • Size (10, 30)
    • Location (100, 208)
  • pbleftuser4
    • Size (10, 30)
    • Location (100, 238)
  • pbleftuser5
    • Size (10, 30)
    • Location (100, 267)

Now, as some of you look at my numbers closely, you may realize that while the picture boxes are 30 units long, they are not equally set apart 30 units. This is because C# has it so some of the picture boxes have a slight gap between them at 30 units apart, so you have to squish them together a bit. Does this affect the actual execution of the project? No. Is it annoying, so much so that I had to change it? Yes.

Left Paddle, But on the Right

Step33.png

Now, having only one side of a Pong game isn't exactly a fun time, so lets make the right side. Simply copy and paste five more of the small picture boxes, name them, set their size, and set their location as such:

  • pbrightuser1
    • Size (10, 30)
    • Location (1150, 149)
  • pbrightuser2
    • Size (10, 30)
    • Location (1150, 178)
  • pbrightuser3
    • Size (10, 30)
    • Location (1150, 208)
  • pbrightuser4
    • Size (10, 30)
    • Location (1150, 238)
  • pbrightuser5
    • Size (10, 30)
    • Location (1150, 267)

Labels

Step34.png
Step35.png
Step41.png
Step36.png
Step37.png
Step38.png
Step39.png
Step40.png
Step42.png

So, labels. Labels allow you to add text to your form, which we will be using for the timer, scorekeeping, and telling you how to start the game.

You will wanna go back to your toolbox and double click on Label, which should drop one inside your form.

As with picture boxes you name them "pb" plus whatever their job is, you do the same with labels, calling them "lbl" instead. For this first label, we'll call it "lblstart".

A new property which labels have and picture boxes don't is the Font Property. Within here, you can change the font, the font style, and the size. For this label, we'll set it to Times New Roman, Bold, and 20pt font. We will also set the location to (487, 338)

Time Label

Step47.png
Step43.png
Step44.png
Step45.png
Step46.png

Lets start working on the timer section down at the bottom. We will create one label to the left side of the divider and one to the right to actually display the time. Create a new label and name it "lbltime". Set the font to:

  • Times New Roman
  • Bold
  • 10

Set the location of this label to (578, 424) and set the Text property to "Time".

Time Label: the Sequel

Step48.png
Step49.png
Step50.png
Step51.png
Step52.png

Oh boy, the sequel! Hopefully it lives up to the original, but we all know sequels are just a cash grab.

Anyhooo, create another label, name it "lbltimer" and set the font to:

  • Times New Roman
  • Bold
  • 10

Set the location to (647, 424) and change the Text to "0:00".

Scoreboard

Step53.png

For this section of the game, create four labels, two for both sides

  • Name: lblleftuser
    • Font: Times New Roman
    • Style: Bold
    • Size: 10
    • Location: (550, 13)
    • Text: Score
  • Name: lblleftuserscore
    • Font: Times New Roman
    • Style: Bold
    • Size: 10
    • Location: (607, 13)
    • Text: 0
  • Name: lblrightuser
    • Font: Times New Roman
    • Style: Bold
    • Size: 10
    • Location: (671, 13)
    • Text: Score
  • Name: lblrightuserscore
    • Font: Times New Roman
    • Style: Bold
    • Size: 10
    • Location: (647, 13)
    • Text: 0

If everything goes well, it should look like the above image. If you are having issues, please refer to previous slides.

Coding: First Stop, Variables

Step54.png

Hey! Good job! You got through the form design, and are now ready to code. If you have not already, double click on the form.

In this section, we have three different types of variables:

  • Random
    • A random function creates a randomly generated number between two numbers. You will only have to make a random function once per form.
  • Int
    • A whole number variable, used when you need a whole number variable
  • String
    • A variable that holds a line (or string) of words.

Right underneath:

public Form1()

{

InitializeComponent();

}

Start copying the variables

There should be:

1 Random Function

23 Ints

1 String

Random Rand = new Random();

int start;

int direction = 1;

int bounce = 3;

int speed = 1;

int balll;

int ballt;

int leftbound;

int rightbound;

int l1;

int l2;

int l3;

int l4;

int l5;

int r1;

int r2;

int r3;

int r4;

int r5;

int min;

int tensec;

int sec;

int lscore;

int rscore;

string time;

Now, when ints are used, they are automatically set to 0. So, for Direction, Bounce, and Speed, we set them equal to a different number.

Form_Load

Step55.png

Please copy the above code into the form_load section by double clicking on the form

Now, in this section, when a form is loaded, these lines of code are fired.

The first two lines of code:

balll = pbball.Left;
ballt = pbball.Top;

Set variables equal to a location. The "Left" function is equal to the x coordinate, and the "Top" Function is set to the y coordinate.

Lets take a look at the location of the ball (621, 208).

balll would be set equal to 621

ballt would be equal to 208

The 3rd and 4th line of code:

leftbound = pbleftuser1.Left;
rightbound = pbrightuser1.Left + 10;

Set variables again, equal to a location. The left bound forms a line for which the ball cannot pass when it interacts with the paddle. The rightbound does the same thing, however, given that the location goes off the top left, we add 10 to it, as the paddles are 10 units wide, so it forms a line on the right side.

The final lines of code:

l1 = pbleftuser1.Top;
l2 = pbleftuser2.Top;

l3 = pbleftuser3.Top;

l4 = pbleftuser4.Top;

l5 = pbleftuser5.Top;

r1 = pbrightuser1.Top;

r2 = pbrightuser2.Top;

r3 = pbrightuser3.Top;

r4 = pbrightuser4.Top;

r5 = pbrightuser5.Top;

Set the variables equal to the Y Coordinate of each of the paddles.

All these variables are used later to set the original position of the paddles and ball, so when the game is reset, they can go to their original position

Timers

Step61.png
Step62.png
Step63.png
Step64.png

Timers are very important for having things move incrementally. Come on now, clocks ticking.

Inside your toolbox there will be a submenu labeled components. At the very bottom there is an item called "Timer." Bring four of those into the form. They should appear at the bottom, 1-4.

Inside the property menu for timers, you have Name, Enabled, GenerateMember, Interval, Modifiers, and Tag. For this project, we will focus on Name, Enabled, and Interval.

Name, is the name of the timer, the address essentially.

Enabled is whether or not the timer is ticking.

Interval is the interval at which the timer ticks. It is in milliseconds, so 1 second would be 1,000 milliseconds, and 1/10 of a second would be 100 milliseconds.

Adjust the four timers accordingly:

  • Name: timerleft
    • Enabled: False
    • Interval: 10
  • Name: timerright
    • Enabled: False
    • Interval: 10
  • Name: timerbounce
    • Enabled: True
    • Interval: 10
  • Name: timertime
    • Enabled: False
    • Interval: 1000

There we have it, the four timers we will need for our project

Timerleft

Step65.png

Lets get started on our timerleft. This timer will trigger whenever the ball is moving to the left.

Copy the code above into your form within the timer (double click on timerleft)

The first line of code:

pbball.Left -= speed;

Makes it so the ball moves to the left. Everytime the timer fires, it goes to the left by the amount which the speed variable is equal to.

So, the speed at the beginning is equal to 1 unit, and the timer fires every 1/100 of a second, meaning the ball will move to the left 100 units every second.

The next time of code would be the If Statements.

if (pbball.Bounds.IntersectsWith(pbleftuser1.Bounds))
{

bounce = 1;

}

This Event for when this If Statement is triggered is when the the Bounds of the Ball Intersects with the Bounds of the Left Paddle, the topmost paddle in this case. That may sound a bit chaotic, but lets simplify it. If the Ball touches the top paddle, the bounce variable is equal to 1. (That bounce variable will make more sense later

The extra long line of code that doesn't fit on the screen is:

if (pbball.Bounds.IntersectsWith(pbleftuser1.Bounds) || pbball.Bounds.IntersectsWith(pbleftuser2.Bounds) || pbball.Bounds.IntersectsWith(pbleftuser3.Bounds) || pbball.Bounds.IntersectsWith(pbleftuser4.Bounds) || pbball.Bounds.IntersectsWith(pbleftuser5.Bounds) && pbball.Left >= leftbound)

The double slash lines mean the If Statement is also an Or Statement, meaning if any of the events are triggered, the code within the If Statement is fired.

The And Statement at the end makes it so the ball must be beyond a certain X Coordinate value, in the event the ball is just barely clicked when passing the paddle, it won't change direction even when it should already be outside of bounds.

The code within the If Statement turns off timerleft and turns on timerright so the ball can then move to the right.

The other section of code is the:

speed += 1;

This increases the speed by one every time the ball touches a paddle, making the ball bounce faster and faster.

The If statement afterwards keeps the speed from going over 30 units per 1/100 of a second, which can cause issues like teleporting through the paddles.

Timerright

Step66.png

This timer is essentially the same as timerleft, except instead of subtracting the speed variable, you add it so it moves to the right, Copy the Code from the image above into timerright.

The bounce section of code is also similar, except instead of the ball intersecting with the pbleftuser pictures boxes, it intersects with the pbrightuser picture boxes.

Another difference is the enabled code towards the bottom. When the ball intersects with the right side, it turns off timerright and turns on timerleft

The super long If Statement is as follows:

if (pbball.Bounds.IntersectsWith(pbrightuser1.Bounds) || pbball.Bounds.IntersectsWith(pbrightuser2.Bounds) || pbball.Bounds.IntersectsWith(pbrightuser3.Bounds) || pbball.Bounds.IntersectsWith(pbrightuser4.Bounds) || pbball.Bounds.IntersectsWith(pbrightuser5.Bounds) && pbball.Left <= rightbound)

Timerbounce

Step67.png
Step68.png
Step69.png

Please copy the above code into the bounce timer.

A new function we are using is case break. How this function works is it takes the variable (in this first vase, bounce). In our last timer, we had the each paddle intersection equal to a bounce, 1-5. 1-5 are the cases. When ending a case, you put "break" to break the line of code.

As you can see, if the ball touches a higher or lower paddle, it moves up or down by two pixels for every timer tick. The center paddle however, makes it go straight outwards.

We then have our Intersection code for the top and bottom picture boxes. When the ball hits the top or bottom, it multiples the direction variable by -1 to change the sign of the variable. This in turn with our previous case break code, allows the ball to be able to bounce all around the screen.

The next section of code is our scoring code. If the x-value (or left value) of our ball is less than 0, the right user wins. This in turn turns off all the timers, makes the start label visible once more, lets the speed and direction back to 1, turns our time variables back to 0, and adds 1 to the right user score.

lblrightuserscore.text = rscore.tostring();

This line of code turns the rscore variable into a string, which you can then use to change the text of the right user score label. For instance, if you scored once, your score would increase to 1, and it would set the label to read 1 instead of 0.

Also reset, is the positions of our paddles and the ball. Given that we took the positions of the paddles and balls when the form loads (in form_load) we can set their positions back to them by just setting the positions to the variables.

The last section of code is simply if the ball goes to the right side (greater than 1000) and the only true difference is the direction and the left score, which adds a point to the left user.

Timertime

Step71.png

The final timer on our list is the one in control of the clock. Please copy the above code into the timertime timer.

Now, every time the timer fires, 1 is added to the sec variable. When sec is equal or greater than 10, it resets sec back to 0, and increases the tensec variable by 1. Then in the next sequence, if tensec is equal or greater than 6, it is reset back to 0 and 1 is added to the min variable.

Then we take our time string and set it equal to:

min + ":" + tensec + sec

This takes our variables and organizes them into a sequence that will resemble a typical analog clock.

We then take our time label and set it equal to our time variable so that it gets displayed.

Key_Down

Step56.png
Step57.png
Step58.png
Step59.png
Step60.png
Step70.png

Lets get going on the user inputs.

Go back to your Form Design page (Form1.cs [Design]*) and go to the form property tab. Click on the lightning bolt and scroll to the property called KeyDown. Double click this property and the coding window should pop up. When a key is pressed, it is sent through here.

Copy the above code according to the pictures.

The first button we will focus on is the Enter Key. We will also be looking at If Statements.

If the event within the paratheses is triggered, it runs the code below it.

if (e.KeyCode == Keys.Enter && lblstart.Visible == true)

This line of code takes the keycode and sets it equal to the enter key. You may also notice the double &&. That makes this If Statement an And Statement as well. So, if both events are triggered at the same time, the code is fired.

lblstart.Visible = false;
timerbounce.Enabled = true;

bounce = 3;

speed = 1;

timertime.Enabled = true;

lbltimer.Text = "0:00";

start = Rand.Next(2) + 1;

.Visible code refers to whether an item is visible, or invisible. So, in this instance when the Enter Key is pressed, and the lblstart label is visible, it makes the label invisible. This line of code also makes the timerbounce enabled, so the ball can bounce around when it hits something.

It also sets bounce to 3, which according to our previous timer code, means the ball will travel directly along the x axis.

The random line of code spits out a number, either 1 or 2 (a random function generates a set number of units starting zero. So whereas the code would actually spit out a 0 or a 1, we add 1 to that to get our 1 or 2)

If the direction equals 1, it goes to the left. If it equals 2, it goes to the right.

The next section of code is our paddle movement code. It is all contained within an If Statement, so if the start label is invisible, the other lines of code can fire. Now, if you look at each If Statement, you will notice that each one is an And Statement as well. If the top paddle of each side is below 10 or above 230, you can move the paddles up and down by 10 units. This is to stop the paddles from going off the screen. We also use the W, S, Up Arrow, and Down arrow (W and S for the left paddle, Up and Down arrows for the right)

Finale

Step73.png

And there we have it! By clicking the green arrow in the top left corner, you will be able to play Pong! Hope you had fun coding and thank you for taking the time to read this.