In this project, we will see how to create a ping pong game on Arduino. You can play with two players. Each player has two buttons—one to move the paddle up and the other to move it down.

A point is scored when the opponent fails to return the ball. The first player to score 10 points wins.

Required Materials

Now, let’s go over the required materials for the project:

  • An Arduino Uno board

  • A 16×2 Liquid Crystal LCD screen

  • 4 Push buttons

  • 5 resistors (1 kilo-ohm each)

  • Connecting wires

#include <LiquidCrystal.h>
#include <avr/interrupt.h>

// Assign the pins for the screen
#define RS 12
#define EN 11
#define D4 6
#define D5 7
#define D6 8
#define D7 9

// Define the buttons that move the paddles
#define Player_1_moveDownButton 10   // Down button for player 1
#define Player_1_moveUpButton 5     // Up button for player 1
#define Player_2_moveDownButton 2   // Down button for player 2
#define Player_2_moveUpButton 3     // Up button for player 2

// Assign the player numbers
#define Player_1 1
#define Player_2 2

// Wait times between ball updates
#define DiagonalballUpdateTime 21
#define HorizontalballUpdateTime 15

// Starting position of the ball  
#define Start_X 35
#define Start_Y 7

#define Button_Pressed (p1_UpButState | p1_DownButState | p2_UpButState | p2_DownButState)

void(* resetFunc) (void) = 0;       

// Global variables for interrupts
volatile boolean x_Up = true;
volatile boolean x_Down = true;

LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);    // Initialize the LCD screen

class Paddle // Class for the paddle
{
  public:
  // Store the value of each row containing the paddle
  uint8_t PaddleColArray[16] = {0,0,0,0,0,4,4,4,0,0,0,0,0,0,0,0};
  
  uint8_t PaddlePos = 6;     // Center of the paddle as the reference to move it
  uint8_t Score = 0;         // Player's score

  void MovePaddleUp()   // When the player presses the up button
  {
    // Check if the paddle doesn't go out of the screen
    if(PaddlePos != 1)
    {
      PaddlePos--;
      PaddleColArray[PaddlePos+2]=0;
      PaddleColArray[PaddlePos-1]=4;
    }
  }

  // When the player presses the down button
  void MovePaddleDown()
  {
    if(PaddlePos != 14)
    {
      PaddlePos++;
      PaddleColArray[PaddlePos-2]=0;
      PaddleColArray[PaddlePos+1]=4;
    }
  }

  // Display paddles with the player numbers
  void PrintPaddles(uint8_t Player_Num)
  {
    if(Player_Num == 2)
    {
      // Each player has a unique number to display
      lcd.createChar(0, PaddleColArray);
      lcd.createChar(1, PaddleColArray+8);

      lcd.setCursor(14, 0);
      lcd.write(byte(0));
      
      lcd.setCursor(14, 1);
      lcd.write(byte(1));
    }
  
     else
    {
      lcd.createChar(2, PaddleColArray);
      lcd.createChar(3, PaddleColArray+8);
  
      lcd.setCursor(1, 0);
      lcd.write(byte(2));

      lcd.setCursor(1, 1);
      lcd.write(byte(3));
    }
  }
};

// Create the two paddles
Paddle p1, p2;

class Print_Game
{
  public:

  // Display text when the game starts
  void Start_Game()
  {
    lcd.print(F("   PING PONG "));
    
    // Move to the second line
    lcd.setCursor(0, 1);
    lcd.print(F("Press a button! "));

    // Variable to check if a button is pressed
    uint8_t p1_UpButState = 0;
    uint8_t p1_DownButState = 0;
    uint8_t p2_UpButState = 0;
    uint8_t p2_DownButState = 0;
    
    // Wait for a button to be pressed
    while(!(Button_Pressed))
    {
      p1_UpButState = ((PIND & (1 << Player_1_moveUpButton)) );
      p1_DownButState = ((PINB & (1 << (Player_1_moveDownButton-8))) );
      p2_UpButState = ((PIND & (1 << Player_2_moveUpButton)) );
      p2_DownButState = ((PIND & (1 << Player_2_moveDownButton)) );
    }
    lcd.clear();        // Clear the screen to start the game
  }

  // Display the score for each player
  void Print_Score()
  {
    // Clear the LCD screen to show the scores
    lcd.clear();
    lcd.print(F("Player_1  Player_2"));
    lcd.setCursor(3 ,1);
    lcd.print(p1.Score);
    lcd.setCursor(12 ,1);
    lcd.print(p2.Score);

    // Scores are displayed for 2 seconds
    delay(2000);

    // Clear the screen to continue the game
    lcd.clear();
  }

  // Display the winner
  void Print_Winner(int Player_Num)
  {
    lcd.setCursor(0 ,0);
    lcd.print(F("   LOST   "));
    lcd.setCursor(1, 1);
    lcd.print(F("Player "));
    lcd.print(Player_Num);
    lcd.setCursor(11 ,1);
    lcd.print(F("wins"));

    // Text remains for 5 seconds
    delay(5000);

    // Reset the game
    resetFunc();
  }
};

Print_Game g;

class Ball // Ball function
{
  private:

  // Flag to reset the ball and paddles when a point is scored
  uint8_t Point_Scored = 0;
  
  uint8_t ballYDir = 0;       
  uint8_t ballXDir = -1;    

  // Ball location
  uint8_t ballY = Start_Y;
  uint8_t ballX = Start_X;
  
  uint8_t ballCharArray[8] = {0, 0, 0, 0, 0, 0, 0, 16};

  public:

  void GenerateBallArray();

  void PrintBall();

  void UpdateBall(uint8_t , uint8_t);

  void AwardAPoint();
};

void Ball :: GenerateBallArray() // Generate the ball
{
  for(uint8_t i=0; i<8; i++)
    {
    if(i == (ballY % 8))
    {
      ballCharArray[i] = 2 << (4 - (ballX % 5));
    }
    else
    {
      ballCharArray[i] = 0;
    }
  }
}

void Ball :: PrintBall() // Display the ball
{
   uint8_t LCDCol = ballX / 5;
  uint8_t LCDRow = (ballY <= 7) ? 0 : 1;
  lcd.createChar(4, ballCharArray);
  lcd.setCursor(LCDCol,LCDRow);
  lcd.write(byte(4));
}

// Update the ball position
void Ball :: UpdateBall(uint8_t P1_PaddlePos, uint8_t P2_PaddlePos)
{
  // Small delay before update
  // The ball moves at the same speed when moving diagonally
  if(ballYDir)          // When the ball moves diagonally
  {
    delay(DiagonalballUpdateTime);
  }
  else                  // When the ball moves horizontally
  {
    delay(HorizontalballUpdateTime);
  }

  // Calculate the next ball position
  
  // If the ball goes out of the paddle
  if((ballX <= 6) || (ballX >= 73))
  {
    AwardAPoint();
  }

  // If the ball hits player 2's paddle
  else if(ballX == 72)
  {
    // if the ball hits the middle of the paddle
    if(ballY == P2_PaddlePos)
    {
      ballXDir = -1;
    }

    // If the ball hits the bottom of the paddle
    else if(ballY == (P2_PaddlePos + 1))
    {
      ballXDir = -1;
      if(ballY == 15)    // If the ball hits the bottom of the paddle at the screen's edge
      {
        ballYDir = -1;
      }
      else
      {
        ballYDir = 1;
      }
    }

    // If the ball hits the top of player 2's paddle
    else if(ballY == (P2_PaddlePos - 1)){
      ballXDir = -1;
      if(ballY == 0)    // If the ball hits the top of the paddle and the top of the screen
      {
        ballYDir = 1;
      }
      else
      {
        ballYDir = -1;
      }
    }
  }

  // If the ball is at the middle of player 1's paddle
  else if(ballX == 7)
  {
    if(ballY == P1_PaddlePos)
    {
      ballXDir = 1;
    }
    // If the ball hits the bottom of the paddle
    else if(ballY == (P1_PaddlePos + 1)){
      ballXDir = 1;
      if(ballY == 15)   // If the ball hits the bottom of the paddle at the screen's edge
      {