Introduction: Pong Using Visual C#

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.

Step 1: STEM Application

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.

Step 2: Starting Your Project

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.

Step 3: Resizing Your Form

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).

Step 4: Sprucing Up the Place

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?

Step 5: Another Bar

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.

Step 6: Center Divider

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!

Step 7: Pong Ball, While Not Actually Being a Ball.

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.

Step 8: Left Paddle

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.

Step 9: Left Paddle, But on the Right

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)

Step 10: Labels

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)

Step 11: Time Label

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".

Step 12: Time Label: the Sequel

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".

Step 13: Scoreboard

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.

Step 14: Coding: First Stop, Variables

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.

Step 15: Form_Load

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

Step 16: Timers

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

Step 17: Timerleft

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.

Step 18: Timerright

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)

Step 19: Timerbounce

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.

Step 20: Timertime

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.

Step 21: Key_Down

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)

Step 22: Finale

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.