Arduino Pong Game

The LED matrices, powered by an Arduino, light up to show a game of Pong. The game can be played by turning the potentiometers to control the movement of the paddles.

Engineer

Miriam R

Area of Interest

Art / Mechanical Engineering / Biology

School

HANC High school

Grade

Incoming Junior

Reflections

Before starting BlueStamp, I knew close to nothing about engineering. Now, through building my project, I learned how to use a dremel, drill, jigsaw, multimeter, and soldering iron. I also learned how to use an Arduino, breadboard, and potentiometers. I now know how to read the resistances of different resistors by looking at their bands, and I have a better understanding of programming. I overcame problems that came up during the process of making the game and I now have more confidence in dealing with issues that may come up in other projects I would create.

I really enjoyed making my project and I’m excited to take my new knowledge of engineering with me in the future.

Final Milestone

Figure1: The whole circuit is inside the box

I finished my final milestone! To complete my project, I uploaded a program for a functioning pong game and set up the box for the display, Arduino, and breadboard to be in.

Figure2: A game of pong in action
Figure3: The score displayed at the end of a round

How it works

The code that I used set the display letters and numbers (ex: PONG, score, etc) as binary variables.

For example, the code below is to display the number 1 when showing the score.

byte one[] = {
  B00111110,
  B00001000,
  B00001000,
  B00001000,
  B00001010,
  B00001100,
  B00001000,
  B00000000
};

To make it look as if the ball is moving around the display, the code used if and else statements.

For example, the code below keeps the ball moving in one direction:

if (dirx == 1) {
  removeball(row, col);
  if (deflect == 0) {
    Row++; // Row = Row + 1;
    Col++; // Col = Col + 1;
    placeball(row, col);
    if (row == 15) { //if current row is 15 (the last) turn around
      deflect = 1; //
    }
    Return;
  }

This part of the code makes the ball switch directions when it hits a wall:

  else {
    Row--; //row = row - 1
    Col++;
    placeball(row, col);
    diry = 1;
    deflect = 0;
    Return;
  }

The code is also set to read the values from the potentiometers and use that to control the paddles. The potentiometers work by changing the resistance depending on how the knob is turned.

This code reads the values and then converts them to an integer from 0 to 13 corresponding to the row of the bottom bit of the paddle:

leftpongval = analogRead(leftpaddle);
leftpongval = map(leftpongval, 0, 1010, 0, 13);
rightpongval = analogRead(rightpaddle);
rightpongval = map(rightpongval, 1020, 20, 0, 13);

Once a player reaches five points, the score is reset to 0-0.

For the box, I cut a rectangle out of the top so the display can sit in and be seen. I used a drill to make holes at the corners of where I needed to cut and then I used a jigsaw to connect the holes and cut out the rectangle. I then needed to drill a small hole on both sides of the box for the wires connected to the potentiometers to come out of the box. This allows for the potentiometers to be turned and the game to be played. Lastly, I needed to drill three larger holes in a row and then file them until they were connected and were in a square shape. This hole is for the USB cord to connect to the power source.

 

I tried a couple of different tools to cut the top of the box. The first thing I tried was a dremel. The dremel was not good to use because it melted the plastic before it was able to cut through it. The next thing I tried was a hacksaw. I drilled the biggest size hole into each of the corners where I was planning to cut but when I tried to put the saw through  the holes, they would not fit. I ended up needing to use a jigsaw to cut the holes. The second issue I had was after I cut the hole and tried putting the matrix threw it. The hole was too big. To fix this, I hot glued cardboard to the top of the box and cut out a smaller rectangle to perfectly fit the matrix.

Code for Pong Game
//We always have to include the library
#include "LedControl.h"
byte rightscore = 0;
byte leftscore = 0 ;
byte pongdisplay[] = { // Used upon start up to display "Pong"
  B00000100,
  B00000100,
  B00000100,
  B00000100,
  B01111100,
  B01000100,
  B01000100,
  B01111100,
  B01111100,
  B01000100,
  B01000100,
  B01000100,
  B01111100,
  B00000000,
  B00000000,
  B00000000,
  B01000100,
  B01000100,
  B01000100,
  B01000100,
  B01111100,
  B00000000,
  B00000000,
  B00000000,
  B01111100,
  B01000000,
  B01000000,
  B01111100,
  B01000100,
  B01000100,
  B01111100,
  B00000000,
};
byte zero[] = { // Used to display a '0' for when displaying the score
  B00000000,
  B00011100,
  B00100010,
  B00100010,
  B00100010,
  B00100010,
  B00011100,
  B00000000
};
byte one[] = { // Used to display a '1' for when displaying the score
  B00111110,
  B00001000,
  B00001000,
  B00001000,
  B00001010,
  B00001100,
  B00001000,
  B00000000
};
byte two[] = { // Used to display a '2' for when displaying the score
  B00000000,
  B00111110,
  B00000010,
  B00001100,
  B00010000,
  B00100000,
  B00100010,
  B00011100
};
byte three[] = { // Used to display a '3' for when displaying the score
  B00000000,
  B00001100,
  B00010010,
  B00010000,
  B00001000,
  B00010010,
  B00010010,
  B00001100
};
byte four[] = { // Used to diplay a '4' for when displaying the score
  B00100000,
  B00100000,
  B00100000,
  B00100000,
  B00111100,
  B00100100,
  B00100100,
  B00100100
};
byte five[] = { // Used to display a '5' for when displaying the score
  B00111100,
  B00100000,
  B00100000,
  B00111100,
  B00000100,
  B00000100,
  B00111100,
  B00000000
};
byte matrix = 0; //variables to help display paddles, scores, and "pong"
byte displayrow = 0;
byte displayindex = 0;
/*
Now we need a LedControl to work with.
pin 12 is connected to the DataIn
pin 11 is connected to the CLK
pin 10 is connected to LOAD
there are 8 matrices to control
*/
int row; //these variables store the location of the ball
int col;
byte deflect; //used if the ball must bounce off a wall
LedControl lc = LedControl(12, 11, 10, 8); //initializes LED controller
byte dirx; //these variables store the direction the ball is moving
byte diry;
byte start; //used to start a new game after a player scores
#define leftpaddle 0 //left pong knob is connected to analog input 0
#define rightpaddle 1 // right pong knob is connected to analog intput 1
int rightpongval; //holds the position of the right paddle
int leftpongval; //holds the position of the left paddle
byte pong[] = { // Stores the position of the ball and paddles, initially set as blank
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000
};
void setup() {
  pinMode(leftpaddle, INPUT); //the paddle is an input.
  pinMode(rightpaddle, INPUT); // the paddle is an input.
  Serial.begin(9600); // serial communication for debugging. Set to 9600 baud
  // These statements below go through and set up the matrices to the given setti  ngs
  lc.shutdown(0, false);
  lc.setIntensity(0, 15);
  lc.clearDisplay(0);
  lc.shutdown(1, false);
  lc.setIntensity(1, 15);
  lc.clearDisplay(1);
  lc.shutdown(2, false);
  lc.setIntensity(2, 15);
  lc.clearDisplay(2);
  lc.shutdown(3, false);
  lc.setIntensity(3, 15);
  lc.clearDisplay(3);
  lc.shutdown(4, false);
  lc.setIntensity(4, 15);
  lc.clearDisplay(4);
  lc.shutdown(5, false);
  lc.setIntensity(5, 15);
  lc.clearDisplay(5);
  lc.shutdown(6, false);
  lc.setIntensity(6, 15);
  lc.clearDisplay(6);
  lc.shutdown(7, false);
  lc.setIntensity(7, 15);
  lc.clearDisplay(7);
  //display the initial "pong" text
  while (matrix < 4) {
    while (displayrow <= 7) {
      lc.setRow(matrix, displayrow, pongdisplay[displayindex]);
      displayrow++;
      displayindex++;
    }
    displayrow = 0;
    matrix++;
  }
  delay(1000);
  displayscreen();
  start = 1;
}
void loop() {
  paddles();
  pongsim();
  displayscreen();
}
void paddles() { //reads data from the paddles and displays that in the array
  // reads in the values from the potentiometers used to control the paddles
  // converts the values to an integer from 0-13 corresponding to the row of the   bottom bit of the paddle
  leftpongval = analogRead(leftpaddle);
  leftpongval = map(leftpongval, 0, 1010, 0, 13);
  rightpongval = analogRead(rightpaddle);
  rightpongval = map(rightpongval, 1020, 20, 0, 13);
  //clears the previous paddle inorder to display the next one
  for (int x = 0; x < 2; x++) {
    for (int i = 0; i < 8; i++) {
      bitClear(pong[i + 32 * x], 0);
      bitClear(pong[24 + i + 32 * x], 7);
    }
  }
  //-------------------------------right paddle
  if (rightpongval < 6) { //display the paddle on the lower matrix
    bitSet(pong[rightpongval + 24], 7);
    bitSet(pong[rightpongval + 25], 7);
    bitSet(pong[rightpongval + 26], 7);
  }
  else if (rightpongval > 7) { // display the paddle on the upper matrix
    bitSet(pong[47 - rightpongval], 0);
    bitSet(pong[47 - rightpongval - 2], 0);
    bitSet(pong[47 - rightpongval - 1], 0);
  }
  else if (rightpongval == 6) { // cases for displaying the paddle across both ma  trices
    bitSet(pong[30], 7);
    bitSet(pong[31], 7);
    bitSet(pong[39], 0);
  }
  else if (rightpongval == 7) {
    bitSet(pong[31], 7);
    bitSet(pong[39], 0);
    bitSet(pong[38], 0);
  }
  //----------------------------------left paddle
  //due to the configuration of the cascading displays, there is a small amount o  f lag when moving the left paddle across matrices
  if (leftpongval < 6) { // display the paddle on the lower matrix
    bitSet(pong[leftpongval], 0);
    bitSet(pong[leftpongval + 1], 0);
    bitSet(pong[leftpongval + 2], 0);
  }
  else if (leftpongval > 7) { // display the paddle on the upper matrix
    bitSet(pong[71 - leftpongval], 7);
    bitSet(pong[71 - leftpongval - 2], 7);
    bitSet(pong[71 - leftpongval - 1], 7);
  }
  else if (leftpongval == 6) { // display the paddle across matrices
    bitSet(pong[6], 0);
    bitSet(pong[7], 0);
    bitSet(pong[63], 7);
  }
  else if (leftpongval == 7) {
    bitSet(pong[7], 0);
    bitSet(pong[63], 7);
    bitSet(pong[62], 7);
  }
}
//this function sets a bit to on, corresponding to a row and column
//used to display the ball, and greatly simplifies other functions
void placeball(int row, int col) {
  if (row > 7) {
    int x = (31 - col) % 8;
    int y = col / 8;
    bitSet(pong[71 - row - 8 * y], x);
  }
else {
  int x = (31 - col) % 8; //
  int y = col / 8;
  bitSet(pong[8 * y + row], 7 - x);
  }
}
//same as the placeball function above, but clears the bit instead
//used when the ball moves to clear the previous position of the ball
void removeball(int row, int col) {
  if (row > 7) {
    int x = (31 - col) % 8;
    int y = col / 8;
    bitClear(pong[71 - row - 8 * y], x);
  }
  else {
    int x = (31 - col) % 8; //
    int y = col / 8;
    bitClear(pong[8 * y + row], 7 - x);
  }
}
//this function controls the movement of the ball
void pongsim() {
  //if the ball is at the edge of the display, call a function to check if it is blocked by the paddle
  if ( (col == 1 && dirx == 0) || (col == 30 && dirx == 1)) {
    ball_meets_paddle();
  }
  if (start == 1) { // Starting a new game
    randomSeed(analogRead(leftpaddle)); // randomSeed is necessary to ensure truly random starting position and movement. Here the input from a paddle is used as input for randomization
    dirx = random(2); // Come up with a random starting left to right or right to left motion
    diry = random(2); // Come up with a random starting up or down movement direction
    col = random(12, 20); // generate a random starting column near the middle of the display
    row = random(4, 12); // generate a random starting row near the middle of the display
    placeball(row, col);
    start = 0; // Set the start varaible back equal to 0
  }
  if (diry == 0) { // If the ball is moving from bottom to top
    if (dirx == 0) { // from right to left
      removeball(row, col);
      if (deflect == 0) { // most of the time, simply move the ball in its direction
        row++;
        col--;
        placeball(row, col);
        if (row == 15) {
          deflect = 1;
        }
        return;
      }
      else { // if the ball is next to an edge we must change its direction to bounce it off the edge
        row--;
        col--;
        placeball(row, col);
        diry = 1;
        deflect = 0;
        return;
      }
    }
  // The comments above should explain all of the stuff below. Some stuff, different parameters.
  if (dirx == 1) { // If the ball is moving from left to right
    removeball(row, col);
    if (deflect == 0) {
      row++;
      col++;
      placeball(row, col);
      if (row == 15) {
        deflect = 1;
      }
      return;
    }
    else {
      row--;
      col++;
      placeball(row, col);
      diry = 1;
      deflect = 0;
      return;
    }
  }
}
//--------------------------------------------diry = 1 below
if (diry == 1) { // If the ball is moving from top to bottom
  if (dirx == 0) { // right to left
    removeball(row, col);
    if (deflect == 0) {
      row--;
      col--;
      placeball(row, col);
      if (row == 0) {
        deflect = 1;
      }
      return;
    }
    else {
      row++;
      col--;
      placeball(row, col);
      diry = 0;
      deflect = 0;
      return;
    }
  }
  if (dirx == 1) { // If the ball is moving from left to right
    removeball(row, col);
    if (deflect == 0) {
      row--;
      col++;
      placeball(row, col);
      if (row == 0) {
        deflect = 1;
      }
      return;
    }
    else {
      row++;
      col++;
      placeball(row, col);
      diry = 0;
      deflect = 0;
      return;
      }
    }
  }
}
//this function simply displays the locations of the paddles and ball stored in the pong[] variable
void displayscreen() {
  matrix = 0;
  displayrow = 0;
  displayindex = 0;
  while (matrix < 8) {
    while (displayrow <= 7) {
      lc.setRow(matrix, displayrow, pong[displayindex]);
      displayrow++;
      displayindex++;
    }
    displayrow = 0;
    matrix++;
  }
}
//this function turns off every LED in case we need to clear the display
void clearscreen() {
  int clearing = 0;
  while (clearing < 64) {
    pong[clearing] = B00000000;
    clearing++;
  }
}
//this function checks if the ball is blocked by the paddle or not
void ball_meets_paddle() {
  tone(9, 500, 100); //begin by sending a signal to the buzzer on either a block or a miss
  if (diry == 0) { //case if the ball is going up
    if (dirx == 0) { //going left
      if (deflect == 1) { // if the ball deflects off wall
        if (leftpongval == 13) { //blocked, ball bounces off both wall and paddle
          diry = 1;
          dirx = 1;
          deflect = 0;
        }
        else { //missed it
          clearscreen();
          start = 1;
          delay(1000);
          scoreleft();
        }
      }
      else if (row - leftpongval >= 0 && row - leftpongval <= 2) { //normal 45 degree bounce
        dirx = 1;
      }
      else if (leftpongval - (row + 1) == 0) { //if the ball hits the corner of the paddle, it bounces straight
        dirx = 1;
        diry = 1;
      }
      else { //missed
        clearscreen();
        start = 1;
        delay(1000);
        scoreleft();
      }
    }
    else if (dirx == 1) { // going right
      if (deflect == 1) { // if the ball deflects off wall
        if (rightpongval == 13) { //blocked, ball counces off both wall and paddle
          diry = 1;
          dirx = 0;
          deflect = 0;
        }
        else { //missed it
          clearscreen();
          start = 1;
          delay(1000);
          scoreright();
        }
      }
      else if (row - rightpongval >= 0 && row - rightpongval <= 2) { //normal 45 degree bounce
        dirx = 0;
      }
      else if (rightpongval - (row + 1) == 0) { //if the ball hits the corner of the paddle, it bounces straight
        dirx = 0;
        diry = 1;
      }
      else { //missed
        clearscreen();
        start = 1;
        delay(1000);
        scoreright();
      }
    }
  }
}
//same logic as the above cases
  else if (diry == 1) { // going down
    if (dirx == 0) { //going left
      if (deflect == 1) { // deflects off wall
        if (leftpongval == 0) { //blocked
          diry = 0;
          dirx = 1;
          deflect = 0;
        }
        else { //missed it
          clearscreen();
          start = 1;
          delay(1000);
          scoreleft();
        }
      }
      else if (row - leftpongval >= 0 && row - leftpongval <= 2) { //normal 45 degree bounce
        dirx = 1;
      }
      else if (row - leftpongval == 3) { //hit the corner and bounce straight
        dirx = 1;
        diry = 0;
      }
      else { //missed
        clearscreen();
        start = 1;
        delay(1000);
        scoreleft();
      }
    }
    else if (dirx == 1) { // going right
      if (deflect == 1) { // deflects off wall
        if (rightpongval == 0) { //blocked
          diry = 0;
          dirx = 0;
          deflect = 0;
        }
        else { //missed it
          clearscreen();
          start = 1;
          delay(1000);
          scoreright();
        }
      }
      else if (row - rightpongval >= 0 && row - rightpongval <= 2) { //normal 45 degree bounce
        dirx = 0;
      }
      else if (row - rightpongval == 3) { //hit the corner and bounce straight
        dirx = 0;
        diry = 0;
      }
      else { //missed
        clearscreen();
        start = 1;
        delay(1000);
        scoreright();
      }
    }
  }
}
//if the ball scores of the left side of the screen, i.e. the right player scores
void scoreleft() {
  clearscreen();
  rightscore++;
  setscore();
  displayscreen(); //increase the score and display it
    if (rightscore== 5) { //if the player has 5 points, flash the score then reset the score to 0-0
      int blinkx = 0;
      while (blinkx < 5) {
      clearscreen();
      displayscreen();
      delay(500);
      setscore();
      displayscreen();
      delay(500);
      blinkx++;
    }
    rightscore = 0;
    leftscore = 0;
  }
  else {
    delay(2000);
  }
  clearscreen();
}
//same as above function, but for the left player scoring
void scoreright() {
  clearscreen();
  leftscore++;
  setscore();
  displayscreen();
  if (leftscore == 5) {
    int blinkx = 0;
    while (blinkx < 5) {
      clearscreen();
      displayscreen();
      delay(500);
      setscore();
      displayscreen();
      delay(500);
      blinkx++;
    }
    rightscore = 0;
    leftscore = 0;
  }
  else {
    delay(2000);
  }
  clearscreen();
}
//this function simply sets the screen to display the score
void setscore() {
  for (int i = 0; i < 8; i++) {
    if (leftscore == 0) {
      pong[i] = zero[i];
    }
    else if (leftscore == 1) {
      pong[i] = one[i];
    }
    else if (leftscore == 2) {
      pong[i] = two[i];
    }
    else if (leftscore == 3) {
      pong[i] = three[i];
    }
    else if (leftscore == 4) {
      pong[i] = four[i];
    }
    else if (leftscore == 5) {
      pong[i] = five[i];
    }
    if (rightscore == 0) {
      pong[i + 24] = zero[i];
    }
    else if (rightscore == 1) {
      pong[i + 24] = one[i];
    }
    else if (rightscore == 2) {
      pong[i + 24] = two[i];
    }
    else if (rightscore == 3) {
      pong[i + 24] = three[i];
    }
    else if (rightscore == 4) {
      pong[i + 24] = four[i];
    }
    else if (rightscore == 5) {
      pong[i + 24] = five[i];
    }
  }
}

First Milestone

How it works

The matrices came with the breakout boards pre attached to each other in two rows of four. I hot glued the two rows together and used wires to connect the pins of the matrices to form the display board. Then I connected the other side of the matrix to the digital pins in the Arduino. I tested the display by uploading a test code to the Arduino. Next I had to wire the buzzer to the Arduino. Before I did that, I needed to solder a resistor onto the buzzer to so it would work properly. I tested it with a different code uploaded to the Arduino. Lastly, I needed to hook up the potentiometers to the Arduino. I soldered three wires onto the three ports on the potentiometers. One of them is for ground, one for 5V, and one for resistance. I used a breadboard for this step because I needed more ground and 5V ports. I found that the resistance of the potentiometer goes from 0 to 11k. I tested it by using a code for the potentiometer to control the beeping of the buzzer.

The first problem I had was when I first started and I didn’t understand anything about the matrices. I looked up a lot of tutorials so I would understand more about matrices and be able to set them up. I also learned more about how to use the Arduino. The second problem was that when I was testing the potentiometers they worked irregularly and the test code didn’t always upload properly. I found that switching the matrix’s  ground and 5V wires from the Arduino to the breadboard made it work better.

Uploading all of the test codes and having to change them slightly to fit my circuit helped me understand more about coding. I also learned how to read the  resistance of different resisters to find the right one. This and my better understanding about the LED matrix and Arduino will help me as I continue my project

For my first milestone, I connected the two LED matrices together and then hooked it up to the Arduino. I also attached the buzzer and potentiometer to the Arduino and then tested everything.

Here is the tutorial I used.

Figure1: This is the display with the buzzer and potentiometers wired to the Arduino
The LED matrix is lighting up according to the test code

Starter Project

Figure2: The hook coming out of the box to flip the switch. Notice the green LED light

My Starter Project is the Useless Machine. It is a black box with a switch on top. When you flip the switch, a hook comes out of the box, pushes the switch back, and then the hook retracts back into the box. It essentially does nothing! I enjoyed building this project because I learned how to solder wires, that wires short circuit when they the cross, and how to use a drill.

Figure1: The assembly of the my starter project can be seen above.

How it works

The machine works by using a motor powered by batteries. When you flip the switch it rotates the motor which is attached to a hook. Once the hook comes up and flips the switch back, the direction of the motor is changed. When the hook comes parallel to the box, the back of it pushes down a kill switch to stop the motor until the switch is flipped again. There is also a light emitting diode (LED). A diode is an electrical component that only allows electricity to flow in one direction. An LED converts electrical energy into light. The LED turns on when the switch is flipped, changes color from red to green when it’s switched back, and turns off with the motor when the button is held.

Here is the website link

The first problem I ran into occurred after I wired the control board and I tried to test it. Both the light and the motor were not working. Some of the wires were crossed and when I fixed that, the light started to work.To make the motor run, I had to resolder some of the ports. The last problem I ran into was when I tried to build the rest of the box around the circuit. The top wasn’t lined up correctly and therefore wasn’t able to click into place. I realized that it was off because the switch that I soldered in was crooked. Since I couldn’t fix that, I made the hole for the switch bigger by drilling it. I learned how to solder wires and that if wires cross each other, they will short circuit and not work. I also learned how to use a drill to make a hole bigger.

I’m now ready to bring all this knowledge into my main project.

Start typing and press Enter to search

Bluestamp Engineering