0

I'm building a little "pong" game in Java.

I'm trying to add a scorekeeper up top that shows the updated score (+1) everytime the player saves the ball with the paddle.

I'm trying to use a JLabel but the problem is that I can't think of a way to continuously update the JLabel each time the paddle is hit.

Any ideas?

My code:

MainPanel Class (the one with the Paddle and Ball and Label)

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

//import swing.graphics.BounceFrame;
//import swing.graphics.Circle;

public class MainPanel extends JPanel implements ActionListener, KeyListener, Runnable{

    public Paddle paddle;
    public Ball ball;

    public MainPanel(){
        ball = new Ball(50, 50, 10); //centerX, centerY, radius
        setSize(300, 300);
        paddle = new Paddle();
        JLabel scoreKeeper = new JLabel("Score" + ball.getScore());
        add(scoreKeeper);
        Thread thread = new Thread(this);
        thread.start();
    }

    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2 = (Graphics2D)g;
        paddle.draw(g2);
        ball.draw(g2);
    }

    public void actionPerformed(ActionEvent e) {
        String direction = e.getActionCommand();

        switch(direction){
            case "left": Paddle.movePaddleLeft(); break;
            case "right": Paddle.movePaddleRight(); break;
        }
        this.repaint();
    }

    public void run() {
        try {
            while(true){
                    ball.move(getBounds());
                repaint();
                Thread.sleep(500/30);
            }
            }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == 37){
            Paddle.movePaddleLeft();
        }
        if (e.getKeyCode() == 39){
            Paddle.movePaddleRight();
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
}

And my Ball class:

import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import java.util.Random;

public class Ball {

    private Ellipse2D ball;
    private double radius;
    private double ballCircumference;
    private Color color;

    private double x;
    private double y;
    private double dx = 5;
    private double dy = 5;

    private int score = 0;
    public int getScore() {
        return score;
    }
    //Boundaries to determine if ball is hit by paddle
    private double criticalBoundaryX;
    private double criticalBoundaryY1; 
    private double criticalBoundaryY2;
    private double paddleHalfwayPoint;
    private boolean inGame = true;
    public void recalculateCriticals(){
        criticalBoundaryX = Paddle.getYPosition() - ballCircumference;
        criticalBoundaryY1 = Paddle.getXPosition()- ballCircumference; //Left boundary
        criticalBoundaryY2 = Paddle.getXPosition()+Paddle.getPaddleWidth()+ballCircumference; //Right Boundary
        paddleHalfwayPoint = (Paddle.getXPosition()+Paddle.getPaddleWidth())/2;
    }

    public Ball(int centerX, int centerY, int radius) {
        this.x = centerX - radius;
        this.y = centerY - radius;
        this.radius = radius;
        ballCircumference = 2*radius;
        Random randomRGB = new Random();
        color = new Color(randomRGB.nextInt(255), randomRGB.nextInt(255), randomRGB.nextInt(255));
        this.ball = new Ellipse2D.Double(x, y, 2*radius, 2*radius);
    }

    public void move(Rectangle2D bounds) {
        recalculateCriticals();
        x += dx;
        y += dy;
        if (x < bounds.getMinX()) {
            x = bounds.getMinX();
            dx = -dx;
        }
        if (x + 2*radius >= bounds.getMaxX()) {
            //System.out.println(bounds.getMaxX());
            x = bounds.getMaxX() - 2*radius;
            dx = -dx;
        }
        if (y < bounds.getMinY()) {
            y = bounds.getMinY();
            dy = -dy;
        }
        if (y > criticalBoundaryX){
             if (x < criticalBoundaryY1 || x > criticalBoundaryY2){
                 inGame = false;
             }
             if (!inGame && hittingEdge(x))
                 dx = -dx;
        }
        if (y > criticalBoundaryX && inGame){ //When it hits the paddle
            changeColor();
            score++;
            y = criticalBoundaryX;
            dy = -dy;
         }
        if (y > bounds.getMaxY()){
            System.out.println("Game Over");
            System.exit(0);
        }
        recalculateCriticals();
        ball.setFrame(x, y, 2*radius, 2*radius);
    }

    public boolean onPaddle(double x){
        return ((x > Paddle.getXPosition()) && (x < Paddle.getXPosition()+Paddle.getPaddleWidth()) && (y > Paddle.getYPosition()-10));
    }
    public boolean hittingEdge(double x){
        return ((x >= criticalBoundaryY1 && x < paddleHalfwayPoint)
                ||
                (x <= criticalBoundaryY1 && x > paddleHalfwayPoint)); //Return true if x is hitting the side edge of the paddle
    }
    public void changeColor(){
        Random randomColor = new Random();
        color = new Color(randomColor.nextInt(255), randomColor.nextInt(255), randomColor.nextInt(255));
    }

    public void draw(Graphics2D g2) {
        g2.setColor(color);
        g2.fill(ball);
    }
}
Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356
CodyBugstein
  • 21,984
  • 61
  • 207
  • 363
  • I can't tell if you're laughing at me or admiring my brilliance – CodyBugstein Feb 05 '13 at 21:51
  • 1
    You could create a class for the score that you'll make observable. You will need to be able to add observers to an instance and each time you set the score you iterate through all the observers and tell them the score has changed(you could easily implement this yourself). Then create an observer in the MainPanel that updates the score on each ValueChangedEvent. Aniket was only laughing at the class name I think. – Vlad Topala Feb 05 '13 at 21:51
  • @Aniket haha that's hilarious! I said "my Ball class"! ..not – CodyBugstein Feb 05 '13 at 21:55
  • @Vlad Can you give an example? – CodyBugstein Feb 05 '13 at 22:04
  • Take a look at this: http://www.vogella.com/articles/DesignPatternObserver/article.html – Vlad Topala Feb 05 '13 at 22:22
  • I think @Aniket 's point was that having a `Ball` class with a member variable called `ball` probably indicates that the Ball class should extend the member variable's type. Your move class basically performs `intersects` against another 2D shape. Why not make use of the existing functions. – Philip Whitehouse Feb 05 '13 at 22:39
  • 1
    Vlad made a good point about needing to implement some kind of observe pattern. Basically, I would create some kind of model that could maintain the data you require. It would be used by the various parts of you application, allowing the paddels (for example) to update the score and provide a listener interface for the score board to be notified when the score changes. – MadProgrammer Feb 05 '13 at 22:44
  • 1
    See also this [answer](http://stackoverflow.com/a/3072979/230513) concerning MVC and the observer pattern. – trashgod Feb 06 '13 at 01:21

1 Answers1

1

The "Java way" of doing this would be to define a listener interface, for example:

public interface BallListener {
  void paddleHit();
}

In the Ball class, you should add a field

private List<BallListener> listeners;

as well as methods

public void addBallListener(BallListener l) { listeners.add(l); }
public void removeBallListener(BallListener l) { listeners.remove(l); }

When the paddle is hit, you go:

for (BallListener l : listeners)
  l.paddleHit();

The main class should implement the BallListener interface, and register itself with the ball (ball.addBallListener(this)).

This approach also enables you to, when needed, inform other parts of your program about different events that happen to the ball (i.e. add a new method to BallListener for each event you'd like to signal).

gcvt
  • 1,482
  • 13
  • 15
  • Also consider [`EventListenerList`](http://docs.oracle.com/javase/7/docs/api/javax/swing/event/EventListenerList.html), found in every `JComponent`. – trashgod Feb 06 '13 at 01:25
  • And what's the in body of paddleHIt()? A static call to a point incrementer? – CodyBugstein Feb 06 '13 at 22:58