0
\$\begingroup\$

I recently created the following code, which is supposed to implement a Pong variation for one player. How can I improve or optimize my code?

Pong class:

import javax.swing.JFrame;

public class Pong extends JFrame {
    private static final int HEIGHT = 500, WIDTH = 900;

    public Pong() {
        super("Pong");
        setSize(WIDTH, HEIGHT);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        add(new PongPanel(this));

        setVisible(true);
    }

    public static void main(String[] args) {
        new Pong();
    }
}

PongPanel class:

import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class PongPanel extends JPanel {
private Racket racket;
private Ball ball;
private JLabel scoreLabel;
private int score = 0;

public PongPanel(Pong game) {
    racket = new Racket(game, game.getHeight() - 100);
    ball = new Ball(game);

    scoreLabel = new JLabel(Integer.toString(score));
    scoreLabel.setFont(new Font("sansserif", Font.PLAIN, 30));
    add(scoreLabel);

    Timer timer = new Timer(5, new TimerHandler());
    timer.start();

    addKeyListener(new KeyHandler());
    setFocusable(true);
}

private void update() {
    racket.updatePosition();
    ball.updatePosition();
    checkCollisionBallSides();
    checkCollisionBallRacket();
    repaint();
}

private void checkCollisionBallSides() {
    if (ball.getX() < 0 || ball.getX() > getWidth() - ball.getWidth() - (getInsets().left + getInsets().right))
        ball.setXA(-ball.getXA());
    else if (ball.getY() < 0)
        ball.setYA(-ball.getYA());
    else if (ball.getY() > getHeight() - ball.getHeight()) {
        JOptionPane.showMessageDialog(null, "Game Over. You scored " + score + ".", "Pong", JOptionPane.INFORMATION_MESSAGE);
        System.exit(0);
    }
}

private void checkCollisionBallRacket() {
    if (ball.getBounds().y + ball.getHeight() == racket.getBounds().y &&
        ball.getBounds().x + ball.getWidth() > racket.getBounds().x &&
        racket.getBounds().x + racket.getWidth() > ball.getBounds().x) {
        ball.setYA(-ball.getYA());
        score++;
        scoreLabel.setText(Integer.toString(score));
    }
}

@Override
public void paint(Graphics g) {
    super.paint(g);
    racket.paint(g);
    ball.paint(g);
}

private class KeyHandler implements KeyListener {
    @Override
    public void keyPressed(KeyEvent e) {
        racket.pressed(e);
    }

    @Override
    public void keyReleased(KeyEvent e) {
        racket.released(e);
    }

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

private class TimerHandler implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        update();
    }
}
}

Racket class:

import java.awt.Graphics;
import java.awt.event.KeyEvent;

public class Racket extends Sprite {
    private final Pong game;

    public Racket(Pong game, int y) {
        super((game.getWidth() - 60) / 2, y, 0, 0, 60, 10);
        this.game = game;
    }

    public void pressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT)
            setXA(-1);
        else if (key == KeyEvent.VK_RIGHT)
            setXA(1);
    }

    public void released(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)
            setXA(0);
    }

    public void updatePosition() {
        if (getX() + getXA() >= 0 && getX() + getXA() < game.getWidth() - getWidth())
            setX(getX() + getXA());
    }

    public void paint(Graphics g) {
        g.fillRect(getX(), getY(), getWidth(), getHeight());
    }
}

Ball class:

import java.awt.Graphics;

public class Ball extends Sprite {

    public Ball() {
        super(0, 0, 1, 1, 30, 30);
    }

    public void updatePosition() {
        setX(getX() + getXA());
        setY(getY() + getYA());
    }

    public void paint(Graphics g) {
        g.fillOval(getX(), getY(), getWidth(), getHeight());
    }
}

Sprite class:

import java.awt.Rectangle;

public class Sprite {
    private int x, y, xa, ya, width, height;

    public Sprite(int x, int y, int xa, int ya, int width, int height) {
        this.x = x;
        this.y = y;
        this.xa = xa;
        this.ya = ya;
        this.width = width;
        this.height = height;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getXA() {
        return xa;
    }

    public int getYA() {
        return ya;
    }

    public int getHeight() {
        return height;
    }

    public int getWidth() {
        return width;
    }

    public Rectangle getBounds() {
        return new Rectangle(x, y, width, height);
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setXA(int xa) {
        this.xa = xa;
    }

    public void setYA(int ya) {
        this.ya = ya;
    }
}
\$\endgroup\$
2
\$\begingroup\$

A few observations

In the PongPanel class, I had to change the following line

ball = new Ball(game);

to

ball = new Ball();

to remove the error. I'm not sure whether the error was in the constructor or the new statement.

In your Pong class, you need to put the Swing components on the Event Dispatch thread (EDT).

In your Pong class, there's no reason to extend JFrame. You can use a JFrame. Here's how I've coded your Pong class now.

package com.ggl.pong;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import com.ggl.pong.view.PongPanel;

public class Pong  {

    private JFrame frame;

    public Pong() {
        frame = new JFrame();
        frame.setTitle("Pong");
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(new PongPanel(this));
        frame.pack();
        frame.setVisible(true);
    }

    public JFrame getFrame() {
        return frame;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                 new Pong();
            }       
        });     
    }
}

Finally, a piece of advice. Have your paddle move a little faster than the ball on the horizontal axis.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.