0

Ball.java

public class Ball {
    int x = 500, y = 10, speed = 1;
    GameBoard board;
    boolean keepRunning = true;
    Thread thread;

    Ball(GameBoard board) {
        this.board = board;
        new Thread(r1).start();
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    Runnable r1 = new Runnable() {
        public void run() {
            try {
                while (true) {
                    if (board.ball.intersects(board.pPaddle)) {
                        speed = -speed;
                    } else {
                        System.out.println(board.ball + " z " + board.pPaddle);
                    }
                    x -= speed;
                    board.repaint();
                    Thread.sleep(10L);

                }
            } catch (InterruptedException iex) {
            }
        }

    };
}

GameBoard.java

@SuppressWarnings("serial")
public class GameBoard extends Canvas {
    Image dbi;
    Graphics db;
    JFrame okno;
    Player p = new Player(this);
     Ball b = new Ball(this);
     Ai a = new Ai(this);
     Rectangle aiPaddle = new Rectangle(10, 590, 10, 50);
     Rectangle pPaddle = new Rectangle(10, 100, 10, 50);
     Rectangle ball = new Rectangle(500, 10, 10, 10);
    GameBoard() {
        okno = new JFrame();
        okno.setTitle("Pink Ponk");
        okno.setSize(600, 300);
        okno.getContentPane().setBackground(Color.black);
        okno.setResizable(false);
        okno.setVisible(true);
        okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        addKeyListener(p);
    }

    public static void main(String[] args) {
        GameBoard gra = new GameBoard();
        gra.okno.add(gra);
    }

    @Override
    public void update(Graphics g) {
        pPaddle.setBounds(p.getX(), p.getY(), 10, 50);
        aiPaddle.setBounds(a.getX(), a.getY(), 10, 50);
        ball.setBounds(b.getX(), b.getY(), 10, 10);
        dbi = createImage(10, 50);
        db = dbi.getGraphics();
        paint(db);
        g.clearRect(0, 0, 600, 300);
        g.drawRect(p.getX(), p.getY(), 10, 50);
        g.fillRect(p.getX(), p.getY(), 10, 50);
        g.drawOval(b.getX(), b.getY(), 10, 10);
        g.fillOval(b.getX(), b.getY(), 10, 10);
    }

    @Override
    public void paint(Graphics g) {
        pPaddle.setBounds(p.getX(), p.getY(), 10, 50);
        aiPaddle.setBounds(a.getX(), a.getY(), 10, 50);
        ball.setBounds(b.getX(), b.getY(), 10, 10);
        g.clearRect(0, 0, 600, 300);
        g.setColor(Color.white);
        g.drawRect(p.getX(), p.getY(), 10, 50);
        g.fillRect(p.getX(), p.getY(), 10, 50);
        g.drawOval(b.getX(), b.getY(), 10, 10);
        g.fillOval(b.getX(), b.getY(), 10, 10);
    }

}

It worked until I wrote this line of code (24 in Ball.java):

if (board.ball.intersects(board.pPaddle))

I'm getting error:

Exception in thread "Thread-0" java.lang.NullPointerException at Ball$1.run(Ball.java:24) at java.lang.Thread.run(Unknown Source)

I'm sure that rectangles in GameBoard.java aren't empty. I don't know what to do.

assylias
  • 321,522
  • 82
  • 660
  • 783
ahoj pepiczki
  • 309
  • 1
  • 3
  • 18

2 Answers2

1

As far as I can see, there are 2 possibilities:

  • board, the argument passed to the Ball's constructor, is null
  • board, the argument passed to the Ball's constructor, is not null but because you start a thread in the constructor, the thread can see your Ball object partially constructed (and for example, ball.board might have not been assigned yet)...

What you sould do:

  1. Check that board is not null (with a print statement for example)
  2. In any case, don't start a new thread in your constructor

You can create the thread in the consctructor and provide another method (start or init for example) that starts the thread.


Once you have done that, you will probably not get your NPE any longer. However, note that the line Ball b = new Ball(this); is executed before Rectangle ball = new Rectangle(500, 10, 10, 10); so if you access board.ball in the Ball's constructor, you will see it null.

In general, you should avoid escaping this in the constructor or an instance initializer (i.e. don't write something like ObjectXX o = new ObjectXX(this);) because this might not be fully constructed.

Community
  • 1
  • 1
assylias
  • 321,522
  • 82
  • 660
  • 783
  • After some testing, I'm inclined to believe that the latter option (board is partially constructed) to be true, this looks like a race condition in constructing and accessing object fields. – esaj Jul 09 '12 at 10:00
0

The ball rectangle could very well be null, you first create the b which starts a thread which will try to access board.ball. ball is created later in the GameBoard constructor.

Roger Lindsjö
  • 11,330
  • 1
  • 42
  • 53