The Pong Game! (Don't sue us Atari!)

In the classic game of Pong, there is a little ball that bounces around off various walls and objects. Importantly, the ball changes direction when it bounces but it never really slows down in speed. This is a big hint that the collisions that the ball is experiencing are elastic collisions. We'll get to what this means before too long. For now, just remember that this is a different kind of collision than we used in the "Planetoids with momentum!" coding activity. That activity focused on perfectly inelastic collisions where two objects stick together.

Step 0. Play around with a crummy version of Pong where the ball never bounces off anything!

Click here to play with the worst version of pong ever! Notice how you can change the location of the paddle by moving the left and right arrow keys. Notice that the ball does not bounce! It is your job to fix it!

Here is the code we are starting with:

function draw(){

// Update location
x += vx*dt;
y += vy*dt;

// 1st if statement
if ( y + blob_radius > height ) {
//vx = ????;  // fix this!
//vy = ????;  // fix this!
}

// 2nd if statement
if ( (x - blob_radius < 0) | (x + blob_radius > width) ) {
//vx = ????;  // fix this!
//vy = ????;  // fix this!
}

// 3rd if statement
//vx = ????;  // fix this!
//vy = ????;  // fix this!
}

if (keyIsDown(LEFT_ARROW)) {
}
if (keyIsDown(RIGHT_ARROW)) {
}

// Draw axes and other stuff
// This will clear the screen and re-draw it
display();

} // end draw()     DO NOT ADD ANY CODE PAST THIS LINE!!!!


Press Play to run the code! Then Press the left and right arrow keys to move around the paddle. You should see something like this:

You will find that the ball never bounces off of anything and it just moves off screen. There are three different if statements that need to be fixed to get the game to work correctly and two more objectives to complete the exercise. Here is what you will likely see after you press play:

If the program can detect that something is wrong with your code it will show a red next to that objective.

If the program can detect that you have completed the objective it will show a green check mark next to that objective.

But the program is not very smart and if it can't tell whether you have completed the objective it will indicate a question mark like this next to that objective.

By the end of this activity your goal is to have green check marks next to all the objectives like this:

Step 1. Each if statement corresponds to a bounce off of a particular thing (the wall, ceiling or paddle)

Each if statement corresponds to a bounce off of a particular thing, either the wall, the ceiling or the paddle. Let's try to figure out which part of the code is relevant to each one:

Step 1a. Which bounce is this? (the first if statement)

Look at this code and decide whether it is relevant to the bounce off of the wall, ceiling or the paddle:

if ( y + blob_radius > height ) {
//vx = ????;  // fix this!
//vy = ????;  // fix this!
}


Advice #1: Remember that blob_radius is fairly small. Does the expression if ( y > height ) make the meaning clearer?

Advice #2: If you're not sure what this does, inside of the if statement set vx = 0; and  vy = 0;, then run the code and see what happens.

Advice #3: Feel free to run the code a few times! Each time you run it the blob will move in a random direction, so you may need to run it a few times before it heads in a useful direction.

Once you figure out which bounce this is referring to you can move on to the next part. Don't worry about the "fix this!" for now! We'll get to that later.

Step 1b. Which bounce is this? (the second if statement)

In the next if statement that we're going to look at it is important to know that the symbol | really just means OR. The following is a silly example that would never work in a real program, but hopefully it's helpful:

if ( (the teacher says I can leave early) | (the bell rings) ) {
print("I can go home");
}


Below is the actual if statement from the code. Look at this code and think about whether it is relevant to the bounce off of the wall, ceiling or the paddle:

if ( (x - blob_radius < 0) | (x + blob_radius > width) ) {
//vx = ????;  // fix this!
//vy = ????;  // fix this!
}


Comment: The blob_radius is overall fairly small so it may be simpler to think about the code written like this:

if ( (x < 0) | (x > width) ) {
//vx = ????;  // fix this!
//vy = ????;  // fix this!
}


Does this help explain which bounce this code is relevant to? If you're still not sure set vx = 0; and vy = 0;, run the code and see what happens.

Step 1c. Which bounce is this? (the third if statement)

We are about to look at the third if statement. It is important to know that the symbol & really just means AND. Here is a silly example that would never work in a real code:

if ( (you like physics) & (you like coding) ) {
print("Go to Ohio State and study computational physics!");
}


Now that you know what & means look at the third if statement:

if ( (y - blob_radius < ypaddle) & (abs(x - xpaddle) < paddle_width/2) ) {
//vx = ????;  // fix this!
//vy = ????;  // fix this!
}


This statement is even more complicated than the other two, but but let's see if we can figure out what it's relevant to. First of all, do you notice something different about the variable names here? This is the first time the variables xpaddle, ypaddle and paddle_width are used. That should be big hint for which bounce this if statement is referring to.

Inside of the if statement go ahead and set vx = 0; and vy = 0; and see what happens. You may need to run the code a few times to figure out what this code does.

Step 2. Think about elastic collisions!

The next step in the program is to figure out what to put down for vx and vy when the ball collides with a surface. But before we can do this we need to think about elastic collisions.

As discussed in the Planetoids with momentum! activity there are three different types of collisions: perfectly inelastic, inelastic and elastic. That programming activity focused on perfectly inelastic collisions where two objects stick to each other.

Both inelastic and perfectly inelastic collisions involve some loss of energy to heat or sound. However, elastic collisions lose a negligible (i.e. ridiculously small) amount energy to heat or sound which means that the total kinetic energy at the beginning (before the collision) and the end (after the collision) will be the same. So if we only have one object, and if pre-collision is $_i$ and post-collision is $_f$ this means that: $${\rm KE}_i = {\rm KE}_f$$ $$\frac{1}{2} m v_i^2 = \frac{1}{2} m v_f^2$$ $$v_i^2 = v_f^2$$

So far so good. Bear in mind that because this is a 2D problem, the initial velocity ($v_i$) and the final (post-collision) velocity ($v_f$) have an x and a y component. This means: $$v_i^2 = v_{xi}^2 + v_{yi}^2$$ $$v_f^2 = v_{xf}^2 + v_{yf}^2$$

Now we have: $$v_{xi}^2 + v_{yi}^2 = v_{xf}^2 + v_{yf}^2$$

This doesn't seem very useful yet, but in a minute it will be all we need to figure out what to put in for vx =  and vy =  in the various parts of the code that we have to fix.

Fun Fact: When gas particles in the air bounce off of a wall or on the ground the type of collision is elastic!

Step 3. Think about the first if statement!

We need to figure out what to put down for vx =  and vy =  for the first if statement. Let's think about what the ball will be doing before the bounce happens. Here is an example:

As you can see, the ball is about to hit the top of the screen. Since the ball is traveling in the +x direction and the +y direction, let's say that $v_{xi} = 5$ and $v_{yi} = 5$.

Here's what the ball will look like after the collision:

The ball is moving in the +x direction (as before) but it is now moving in the -y direction (instead of the +y direction as before). This means that $v_{xf} > 0$ and $v_{yf} < 0$.

There is one last thing that you need to know to figure out $v_{xf}$ and $v_{yf}$ and that thing is that the acceleration in this case is in the y direction (not the x direction). This means that the velocity in the x direction doesn't change: $$v_{xi} = v_{xf}$$

This means that since $v_{xi} = 5$ then $v_{xf} = 5$. Now we just need to figure out $v_{yf}$.

Step 4. Solve the riddle!

Just to review, earlier we learned that this is true of our collison: $$v_{xi}^2 + v_{yi}^2 = v_{xf}^2 + v_{yf}^2$$

We know that $v_{xi} = 5$ and $v_{yi} = 5$ and we learned that $$v_{xi} = v_{xf} = 5$$

This means that we have the following riddle $$5^2 + 5^2 = 5^2 + v_{yf}^2$$

Solve for $v_{yf}$. It seems pretty simple but here's the riddle: $v_{yf}$ is NOT equal to 5

Step 5. Modify the code for the first if statement

Hopefully you have come to the realization that if the ball is bouncing off of the top of the screen, then, $v_{xf} = v_{xi}$ and $v_{yf} = - v_{yi}$. Sorry if this gives away the riddle. We are now ready to fix the part of the if statement that needed fixing:

 if ( y + blob_radius > height ) {
vx = ????;  // fix this!
vy = ????;  // fix this!
}


Remember that we are in computer world (not math world) which means that expressions like vx = ????; mens that we are giving vx a new value. Since in our collison we have $v_{xf} = v_{xi}$ and $v_{yf} = - v_{yi}$ we can write:

 if ( y + blob_radius > height ) {
vx =  vx;
vy = -vy;
}


Try it out and see if this can get the ball to bounce like you expect. Here is how the code should behave at this stage. FYI, because the initial direction of the ball is randomized, you may need to run the code a few times in order to get the ball to head upwards.

Note: If you noticed that the line vx = vx; doesn't do anything, you're absolutely right. It's cool if you just take that line out. Makes the code shorter. Or leave it in. It's up to you.

Step 6. Modify the code for the second if statement

Here again is the second if statement:

if ( (x - blob_radius < 0) | (x + blob_radius > width) ) {
vx = ????;  // fix this!
vy = ????;  // fix this!
}


We're not going to give you as much help with "fixing" the problem, but we will tell you that because the collision will be elastic, this expression remains true: $$v_{xi}^2 + v_{yi}^2 = v_{xf}^2 + v_{yf}^2$$

However, because the collision is in a different direction than in the first if statement, it will not work to simply copy paste what you had there into the second if statement (but you are welcome to try). (Hint: The result is still very simple, and there are minus signs involved.)

If you do this right your code should behave like this. Feel free to run the code a few times until the ball moves in a direction that helps you figure out if the bounce is working right.

Step 7. Modify the code for the third if statement

Here again is the third if statement:

if ( (y - blob_radius < ypaddle) & (abs(x - xpaddle) < paddle_width/2) ) {
vx = ????;  // fix this!
vy = ????;  // fix this!
}


By now you have probably guessed (correctly) that this code deals with the ball bouncing off of the paddle. We're not going to just give you the answer, but you may be relieved to know that the collison is still elastic, and because the direction of the acceleration is in the y direction, the correct answer is going to look a lot like the one for the first if statement (which has the object bouncing off the top of the screen).

If the right answer still seems unclear, just try out some things and throw in some minus signs and run the program to see what happens. There's no harm in guessing. If you do it right your code should behave like this

After display(); you can add this code and it will cause the game to end if the ball gets to close to the bottom:

    if (y-blob_radius < 0) {
drawText('Game Over!',0.42*width,height/2);
exit();
}


If you copy this into your code then your program should behave like this

Step 9. Add code to show the path of the ball

After display(); you can add this code and it will show the path of the ship:

    for( i = 0; i < xhistory.length ; i+= 1) {
drawPoint(xhistory[i],yhistory[i]);
}


If you copy this into your code then your program should behave like this

Have fun!

Optional Challenges:

Challenge #1:  Make the game start over

Here is the main part of the code that you will want to modify:

    if (y-blob_radius < 0) {     drawText('Game Over!',0.42*width,height/2);      exit();    }

Hint #1: remove exit() because that will end the program

Hint #2: Put the ball back in the middle of the screen (x = 375;  y = 250;)

Hint #3: Use this code to give the ball a new velocity

vx = random(-vspeed,vspeed);
vy = random(-vspeed,vspeed);

Hint #3: Increase vspeed each time so it goes faster and faster

Bonus: add a point system!  Create a variable to keep track of how many game overs have happened.

Challenge #2: Increase the initial speed

Complete challenge #1. Wouldn't it be more fun if the initial speed of the blob gets faster and faster. How would you configure the code to do that automatically?

Hint:  when you put the blob back where it started, and give it a new velocity, change the value of vspeed

Challenge #3: Add a second player

The traditional game of pong involves two players, not just one. The simplest way to do this would be to modify the code so that one player uses the arrow keys to move a paddle, and another player uses the A and D keys on the keyboard to move another paddle that would be at the top of the screen instead of the bottom.

Here is some code you can use to allow the A and D keys to move another paddle:

     if (keyIsDown(65)) {   // the A key on the keyboard
}
if (keyIsDown(68)) {   // the D key on the keyboard
}

If you are wondering where the 65 and 68 came from, there is a thing called the "Javascript Event keyCode" that has every key on your keyboard mapped to some number. To see which keys correspond to which numbers you can go to this site keycode.info

Hint #1: You will need to create new variables (xpaddle2 and ypaddle2) at the top of the code for the second paddle.

Hint #2: Use the drawLine function to draw another paddle at the top of the screen.

Hint #3: Comment out this if statement:

  if ( y + blob_radius > height ) {


and replace it with a new Game Over if statement that checks if the ball is heading off the screen at the top.

Advice for iPad users:  For this code to work, you need to be running iOS13 or later. The iOS13 update became available as a free update for iPad in fall 2019. iOS13 for iPad is sometimes referred to as iPadOS.