×

Search anything:

Pong in Java [project]

Binary Tree book by OpenGenus

Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

In this article at OpenGenus, we will develop a prototype of Basic Pong game in Java Programming Language.

Table of Contents

  1. Introduction
  2. Rules
  3. Code Explanation
  4. Implementation
  5. Conclusion

Introduction

Pong is a classic arcade game that was originally released in 1972, and it is considered one of the earliest video games. The game is a simple two-dimensional sports simulation that emulates table tennis or ping pong.

In Pong, two players control paddles on either side of the screen, moving them up and down to hit a ball back and forth. The objective is to prevent the ball from going past the player's paddle while trying to send it past the opponent's paddle. Each time the ball successfully passes the opponent's paddle, the player scores a point. The game continues until a predetermined score or time limit is reached, and the player with the higher score wins.

Creating a Pong game in Java allows developers to practice and demonstrate their programming skills while exploring various concepts, such as user input handling, game physics, collision detection, and graphical rendering. Java's object-oriented nature and libraries like Swing and AWT make it a suitable choice for developing simple graphical games like Pong.

Pong-1
Pong.png

Rules

The rules of the classic Pong game are straightforward and easy to follow. To play Pong on a computer, you will typically control the paddles using the keyboard. Here are the basic rules:

  1. Game Setup:

    • Pong is a two-player game where each player controls a paddle on either side of the screen.
    • The game starts with the ball placed at the center of the screen, and each player's paddle positioned vertically at the center of their side.
  2. Player Controls:

    • Player 1 (usually on the left side) controls their paddle using the keys 'W' (move up) and 'S' (move down).
    • Player 2 (usually on the right side) controls their paddle using the arrow keys 'Up' (move up) and 'Down' (move down).
  3. Ball Movement:

    • The ball starts moving at the beginning of the game in a random direction, either to the left or right.
    • Once the game starts, the ball's movement is continuous and bounces off the walls and paddles.
  4. Scoring:

    • The objective of the game is to score points by making the ball pass the opponent's paddle and hit the wall behind them.
    • Each time the ball passes a paddle and hits the wall, the opponent scores a point.
    • The player who scores the point gets the privilege to serve the ball for the next round.
  5. Winning the Game:

    • The game continues until a predetermined score or time limit is reached.
    • The player who first reaches the set score (commonly 10 points) is declared the winner.
  6. Ball Speed Increase:

    • In some versions of Pong, the ball's speed may increase after a certain number of points have been scored, making the game more challenging.
  7. Collision Behavior:

    • When the ball collides with a paddle, it changes direction horizontally.
    • When the ball collides with the top or bottom wall, it changes direction vertically, simulating bouncing off the walls.

These rules form the foundation of the classic Pong game. When playing Pong on a computer, the game should follow these rules, and players must use the designated keys to control their paddles and try to outmaneuver their opponent to score points.

Code Explanation

In this section, we will break down the building blocks of the code into smaller code snippets, provide detailed explanations for each part for better understanding and clarity.

  1. Import Statements:

These are the import statements that bring in the necessary classes and interfaces for creating the game window, handling graphics, and managing keyboard events.

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
  1. Class Declaration:

This line declares a class named "Pong" that extends the JFrame class (which provides a window) and implements the KeyListener interface (for handling keyboard events).

public class Pong extends JFrame implements KeyListener {
  1. Constants:

These constants define various values used in the game, such as the window dimensions, paddle dimensions, ball size, and movement speeds.

private static final int WIDTH = 640;
private static final int HEIGHT = 480;
private static final int PADDLE_WIDTH = 10;
private static final int PADDLE_HEIGHT = 60;
private static final int BALL_SIZE = 10;
private static final int PADDLE_SPEED = 5;
private static final int BALL_SPEED = 3;
  1. Instance Variables:

These instance variables hold the current positions and speeds of the paddles and the ball.

private int paddle1Y;
private int paddle2Y;
private int ballX;
private int ballY;
private int ballXSpeed;
private int ballYSpeed;
  1. Constructor:

This is the constructor for the Pong class. It sets up the initial state of the game, such as the window title, size, and default close operation. It also initializes the instance variables and adds the key listener to the game window.

public Pong() {
        setTitle("Pong");
        setSize(WIDTH, HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        setLocationRelativeTo(null);

        addKeyListener(this);
        setFocusable(true);

        paddle1Y = HEIGHT / 2 - PADDLE_HEIGHT / 2;
        paddle2Y = HEIGHT / 2 - PADDLE_HEIGHT / 2;
        ballX = WIDTH / 2 - BALL_SIZE / 2;
        ballY = HEIGHT / 2 - BALL_SIZE / 2;
        ballXSpeed = BALL_SPEED;
        ballYSpeed = BALL_SPEED;
}
  1. Paddle Movement Methods:

These methods handle the movement of the paddles based on keyboard input.

  • movePaddle1Up() : This method is responsible for moving the paddle of Player 1 (the left-side paddle) upwards. It decreases the paddle1Y variable (which represents the vertical position of the paddle) by the constant PADDLE_SPEED.
  • movePaddle1Down() : This method handles the movement of the paddle of Player 1 (left-side paddle) downwards. It increases the paddle1Y variable by the PADDLE_SPEED.
  • movePaddle2Up() : This method is responsible for moving the paddle of Player 2 (the right-side paddle) upwards. It decreases the paddle2Y variable (representing the vertical position of the paddle) by the PADDLE_SPEED.
  • movePaddle2Down() : This method handles the movement of the paddle of Player 2 (right-side paddle) downwards. It increases the paddle2Y variable by the PADDLE_SPEED.
public void movePaddle1Up() {
    paddle1Y -= PADDLE_SPEED;
    if (paddle1Y < 0) {
        paddle1Y = 0;
    }
}
public void movePaddle1Down() {
        paddle1Y += PADDLE_SPEED;
        if (paddle1Y > HEIGHT - PADDLE_HEIGHT) {
            paddle1Y = HEIGHT - PADDLE_HEIGHT;
        }
    }

public void movePaddle2Up() {
        paddle2Y -= PADDLE_SPEED;
        if (paddle2Y < 0) {
            paddle2Y = 0;
        }
    }

public void movePaddle2Down() {
        paddle2Y += PADDLE_SPEED;
        if (paddle2Y > HEIGHT - PADDLE_HEIGHT) {
            paddle2Y = HEIGHT - PADDLE_HEIGHT;
        }
    }
  1. Ball Movement and Collision Detection:

The moveBall() method handles the movement of the ball based on its current position and speed. It also performs collision detection with the paddles and walls. If the ball goes out of bounds, the resetGame() method is called to reset the ball's position and speed.

  • Updating Ball Position : ballX and ballY determines the ball's movement speed in the horizontal direction ballXSpeed and in vertical direction ballYSpeed.

  • Collision Detection with Paddles:

    • ballX <= PADDLE_WIDTH: This condition checks if the ball has collided with the left paddle (Paddle 1). PADDLE_WIDTH represents the width of the paddle.
    • ballX >= WIDTH - PADDLE_WIDTH - BALL_SIZE: This condition checks if the ball has collided with the right paddle (Paddle 2).
  • Collision Detection with Walls:

    • (ballY <= 0 || ballY >= HEIGHT - BALL_SIZE): This condition checks if the ball has collided with either the top or bottom wall of the game window.
    • If a collision occurs with the top or bottom wall, the ballYSpeed is negated to change the direction of the ball, simulating a bounce off the wall.
  • Out of Bounds Check:

    • (ballX < 0 || ballX > WIDTH - BALL_SIZE): This condition checks if the ball has gone out of bounds to the left or right of the game window.
    • If the ball goes out of bounds, the resetGame() method is called to reset the ball's position and speed, effectively starting a new round.
public void moveBall() {
    ballX += ballXSpeed;
    ballY += ballYSpeed;

    // Check collision with paddles
    if (ballX <= PADDLE_WIDTH && ballY + BALL_SIZE >= paddle1Y && ballY <= paddle1Y + PADDLE_HEIGHT) {
        ballXSpeed = BALL_SPEED;
    } else if (ballX >= WIDTH - PADDLE_WIDTH - BALL_SIZE && ballY + BALL_SIZE >= paddle2Y && ballY <= paddle2Y + PADDLE_HEIGHT) {
        ballXSpeed = -BALL_SPEED;
    }

    // Check collision with walls
    if (ballY <= 0 || ballY >= HEIGHT - BALL_SIZE) {
        ballYSpeed = -ballYSpeed;
    }

    // Check if ball is out of bounds
    if (ballX < 0 || ballX > WIDTH - BALL_SIZE) {
        resetGame();
    }
}
  1. Rendering the Game:

The paint(Graphics g) method is an overridden method from the JFrame class and is automatically called by the Java Swing library whenever the game window needs to be redrawn, such as when it's first displayed or when the repaint() method is called. It uses the Graphics object to draw the paddles and the ball at their current positions.

public void paint(Graphics g) {
    super.paint(g);

    g.setColor(Color.BLACK);
    g.fillRect(0, 0, WIDTH, HEIGHT);

    g.setColor(Color.WHITE);
    g.fillRect(PADDLE_WIDTH, paddle1Y, PADDLE_WIDTH, PADDLE_HEIGHT);
    g.fillRect(WIDTH - 2 * PADDLE_WIDTH, paddle2Y, PADDLE_WIDTH, PADDLE_HEIGHT);
    g.fillOval(ballX, ballY, BALL_SIZE, BALL_SIZE);

    Toolkit.getDefaultToolkit().sync();
}
  1. Main Method:

The main method is the entry point of the program. It creates an instance of the Pong class, sets it visible, and enters a game loop. In the loop, the ball is moved, the game window is repainted, and a short delay is introduced between iterations.

public static void main(String[] args) {
        Pong game = new Pong();
        game.setVisible(true);

        while (true) {
            game.moveBall();
            game.repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
}
  1. KeyListener Methods:

These methods are required to implement the KeyListener interface. They handle keyboard events such as key presses and releases. In this code

  • keyTyped() method is triggered when a key press is followed by a key release. Since it is not utilized in the game, it remains empty in the code.
  • keyPressed(KeyEvent e) method is called when a key is pressed on the keyboard.The method then uses a series of if statements to check which key was pressed, and based on the key, it calls the corresponding paddle movement methods (movePaddle1Up(), movePaddle1Down(), movePaddle2Up(), or movePaddle2Down()).
  • This way, when the player presses either 'W', 'S', 'Up', or 'Down' keys, the corresponding paddle moves accordingly.
  • keyReleased(KeyEvent e) method is called when a key that was previously pressed is released (the key is no longer being held down).
@Override
    public void keyTyped(KeyEvent e) {
    }

@Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {
            movePaddle1Up();
        } else if (e.getKeyCode() == KeyEvent.VK_S) {
            movePaddle1Down();
        } else if (e.getKeyCode() == KeyEvent.VK_UP) {
            movePaddle2Up();
        } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            movePaddle2Down();
        }
    }
@Override
    public void keyReleased(KeyEvent e) {
    }

That covers the main segments of the Pong game code. Together, let's create a simple implementation of the Pong game in Java, with paddles that can be controlled using the keyboard and a ball that bounces off the paddles and walls.

Implementation

The basic implementation of Pong in Java involves creating a graphical window to display the game, handling keyboard inputs to control the paddles, updating the ball's position and direction based on its collisions with paddles and walls, and continuously repainting the game window to create the illusion of motion.

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class Pong extends JFrame implements KeyListener {
    private static final int WIDTH = 640;
    private static final int HEIGHT = 480;
    private static final int PADDLE_WIDTH = 10;
    private static final int PADDLE_HEIGHT = 60;
    private static final int BALL_SIZE = 10;
    private static final int PADDLE_SPEED = 5;
    private static final int BALL_SPEED = 3;

    private int paddle1Y;
    private int paddle2Y;
    private int ballX;
    private int ballY;
    private int ballXSpeed;
    private int ballYSpeed;

    public Pong() {
        setTitle("Pong");
        setSize(WIDTH, HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        setLocationRelativeTo(null);

        addKeyListener(this);
        setFocusable(true);

        paddle1Y = HEIGHT / 2 - PADDLE_HEIGHT / 2;
        paddle2Y = HEIGHT / 2 - PADDLE_HEIGHT / 2;
        ballX = WIDTH / 2 - BALL_SIZE / 2;
        ballY = HEIGHT / 2 - BALL_SIZE / 2;
        ballXSpeed = BALL_SPEED;
        ballYSpeed = BALL_SPEED;
    }

    public void movePaddle1Up() {
        paddle1Y -= PADDLE_SPEED;
        if (paddle1Y < 0) {
            paddle1Y = 0;
        }
    }

    public void movePaddle1Down() {
        paddle1Y += PADDLE_SPEED;
        if (paddle1Y > HEIGHT - PADDLE_HEIGHT) {
            paddle1Y = HEIGHT - PADDLE_HEIGHT;
        }
    }

    public void movePaddle2Up() {
        paddle2Y -= PADDLE_SPEED;
        if (paddle2Y < 0) {
            paddle2Y = 0;
        }
    }

    public void movePaddle2Down() {
        paddle2Y += PADDLE_SPEED;
        if (paddle2Y > HEIGHT - PADDLE_HEIGHT) {
            paddle2Y = HEIGHT - PADDLE_HEIGHT;
        }
    }

    public void moveBall() {
        ballX += ballXSpeed;
        ballY += ballYSpeed;

        // Check collision with paddles
        if (ballX <= PADDLE_WIDTH && ballY + BALL_SIZE >= paddle1Y && ballY <= paddle1Y + PADDLE_HEIGHT) {
            ballXSpeed = BALL_SPEED;
        } else if (ballX >= WIDTH - PADDLE_WIDTH - BALL_SIZE && ballY + BALL_SIZE >= paddle2Y && ballY <= paddle2Y + PADDLE_HEIGHT) {
            ballXSpeed = -BALL_SPEED;
        }

        // Check collision with walls
        if (ballY <= 0 || ballY >= HEIGHT - BALL_SIZE) {
            ballYSpeed = -ballYSpeed;
        }

        // Check if ball is out of bounds
        if (ballX < 0 || ballX > WIDTH - BALL_SIZE) {
            resetGame();
        }
    }

    public void resetGame() {
        ballX = WIDTH / 2 - BALL_SIZE / 2;
        ballY = HEIGHT / 2 - BALL_SIZE / 2;
        ballXSpeed = BALL_SPEED;
        ballYSpeed = BALL_SPEED;
    }

    public void paint(Graphics g) {
        super.paint(g);

        g.setColor(Color.BLACK);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        g.setColor(Color.WHITE);
        g.fillRect(PADDLE_WIDTH, paddle1Y, PADDLE_WIDTH, PADDLE_HEIGHT);
        g.fillRect(WIDTH - 2 * PADDLE_WIDTH, paddle2Y, PADDLE_WIDTH, PADDLE_HEIGHT);
        g.fillOval(ballX, ballY, BALL_SIZE, BALL_SIZE);

        Toolkit.getDefaultToolkit().sync();
    }

    public static void main(String[] args) {
        Pong game = new Pong();
        game.setVisible(true);

        while (true) {
            game.moveBall();
            game.repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {
            movePaddle1Up();
        } else if (e.getKeyCode() == KeyEvent.VK_S) {
            movePaddle1Down();
        } else if (e.getKeyCode() == KeyEvent.VK_UP) {
            movePaddle2Up();
        } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            movePaddle2Down();
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
}

Conclusion

Developing a Pong game in Java can serve as a foundation for more complex game projects and provides a hands-on learning experience in game development and programming concepts. Additionally, you can further enhance the game by adding features like sound effects, different difficulty levels, or even implementing networked multiplayer functionality.

With this article at OpenGenus, you have gained valuable knowledge on developing a prototype of "Basic Pong in Java".

Pong in Java [project]
Share this