Results 1 to 18 of 18
- 07-10-2009, 12:46 AM #1
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
NullPointerException even when class is instantiated as expected
Hello, I am new to Java and am practicing by writing a simple game of Pong.
I have a PongBall class that defines some simple behaviors of a pong ball, and a PongPanel class that instantiates the class into an array I have declared as follows:
private PongBall[] pongBalls = new PongBall[5];
(the goal is to have up to 5 pong balls moving independently on the screen at once)
I instantiate the class by:
By default, the ballinmotion boolean variable is initialized to be false.Java Code:if (!ballinmotion) { //at the start of the program [COLOR="Red"]pongBalls[0] = new PongBall();[/COLOR] if (pongBalls[0] instanceof PongBall) { i++; //so the iterator when adding balls based on score is used, it doesnt overlap the starting ball. debuginfo3 = "ball 0 spawned from ballinmotion check at first run through of paintComponent method"; } randomstart = (int)(Math.floor(Math.random() * 4 + 1)); //random starting ballinmotion = true; }
This if statement and instantiation is done inside my "paintComponent(Graphics g)" method, and I get the exception thrown where I am trying to access this object for the first time, here:
Here is the first few of dozens of lines of compiler errors:Java Code:for (int x = 0; x < pongBalls.length; x++) { //draw all the balls in their current positions g.setColor(Color.BLACK); g.fillOval(pongBalls[x].getX(), pongBalls[x].getY(), 14, 14); //generates null ptr exception... }
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at PongPanel.paintComponent(PongPanel.java:201)
at javax.swing.JComponent.paint(JComponent.java:1029)
at javax.swing.JComponent.paintChildren(JComponent.ja va:864)
at javax.swing.JComponent.paint(JComponent.java:1038)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:5 67)
at javax.swing.JComponent.paintChildren(JComponent.ja va:864)
at javax.swing.JComponent.paintToOffscreen(JComponent .java:5131)
at javax.swing.RepaintManager$PaintManager.paintDoubl eBuffered(RepaintManager.java:1475)
at javax.swing.RepaintManager$PaintManager.paint(Repa intManager.java:1406)
at javax.swing.RepaintManager.paint(RepaintManager.ja va:1220)
at javax.swing.JComponent.paint(JComponent.java:1015)
the bold line is where I tried to access the object for the first time;
It might be important to note that when I try/catch for the exception so that the window opens and displays the "debuginfo3" string, the if statement behaves as if the pongBalls[0] is an 'instanceof' the class I am trying to instantiate, "PongBall". (the debuginfo3 string displays the message defined in the body of the if statement.Java Code:for (int x = 0; x < pongBalls.length; x++) { //draw all the balls in their current positions g.setColor(Color.BLACK); [B]g.fillOval(pongBalls[x].getX(), pongBalls[x].getY(), 14, 14);[/B] //generates null ptr exception... }
If there is anything I can post to make my problem clearer, I will be happy to do so. Thanks in advance for any replies/insight as to what I am doing wrong.
-
I see that you try to instantiate pongBalls[0], but how many of the other PongBalls in the array do you instantiate? You may need to post all of your code, indicate the line where your exception is thrown, and note (using System.out.println) the value of the array's index when the exception is thrown.
- 07-10-2009, 03:57 AM #3
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
Thanks for the reply. My full source code for PongPanel.java is as follows:
The full source code for the PongBall class is as follows:Java Code:import java.awt.*; import java.awt.event.*; import javax.swing.JPanel; import javax.swing.Timer; @SuppressWarnings("serial") public class PongPanel extends JPanel { public PongPanel() { //constructor MouseHandler listener = new MouseHandler(); addMouseListener(listener); addMouseMotionListener(listener); moveBall action = new moveBall(); Timer timer = new Timer(10, action); timer.setInitialDelay(2000); //2 second initial delay timer.start(); } private int mouseX; private int rightbound = 1235; private int leftbound = 50; private int bottombound = 635; private int topbound = 50; private int i = 0; //iterator for array of objects private PongBall[] pongBalls = new PongBall[5]; private int lives = 6; private int pts = 0; private int loopcount = 0; private int randomstart; private int balltodraw; private String debuginfo = "no direction yet..."; private String debuginfo2 = "no case executed yet..."; private String debuginfo3 = "no ball spawned yet..."; private String livesremaining = ""; private String points = "Score: " + pts; private boolean redrawball = true; private boolean ballinmotion = false; private boolean mouseMoved = false; private boolean addball = false; public class moveBall implements ActionListener { public void actionPerformed(ActionEvent evt) { if (lives == 0) { debuginfo = "Game Over"; return; } //iterate through the balls for (int y = 0; y < pongBalls.length; y++) { if (!pongBalls[y].hasContactedBound()) { switch(randomstart) { case 1: debuginfo2 = "case 1 executed... for ball " + y; pongBalls[y].setDirY(PongBall.DirectionY.DOWN); pongBalls[y].setDirX(PongBall.DirectionX.LEFT); case 2: debuginfo2 = "case 2 executed... for ball " + y; pongBalls[y].setDirY(PongBall.DirectionY.DOWN); pongBalls[y].setDirX(PongBall.DirectionX.RIGHT); case 3: debuginfo2 = "case 3 executed... for ball " + y; pongBalls[y].setDirY(PongBall.DirectionY.UP); pongBalls[y].setDirX(PongBall.DirectionX.LEFT); case 4: debuginfo2 = "case 4 executed... for ball " + y; pongBalls[y].setDirY(PongBall.DirectionY.UP); pongBalls[y].setDirX(PongBall.DirectionX.RIGHT); } } //now determine the direction based on if the ball has hit a bound or paddle... for (loopcount = 0; loopcount < 4; loopcount++) { //for (int y = 0; y < pongBalls.length; y++) { if (pongBalls[y].getX() == rightbound) { pongBalls[y].setDirX(PongBall.DirectionX.LEFT); pongBalls[y].setContactedBound(); } if (pongBalls[y].getX() == leftbound) { pongBalls[y].setDirX(PongBall.DirectionX.RIGHT); pongBalls[y].setContactedBound(); } if (pongBalls[y].getY() == topbound) { pongBalls[y].setDirY(PongBall.DirectionY.DOWN); pongBalls[y].setContactedBound(); } if (pongBalls[y].getY() == bottombound) { //user fails pongBalls[y].setContactedBound(); lives--; //take away a life. redrawball = true; //redraw a ball balltodraw = y; //need to also set a delay for the timer, how to do this? } if ((pongBalls[y].getX() >= mouseX-5 && pongBalls[y].getX() <= mouseX+101) && (pongBalls[y].getY() == 485) && pongBalls[y].getDirY() == PongBall.DirectionY.DOWN) { //if the ball hits the //paddle on the way down... pongBalls[y].setDirY(PongBall.DirectionY.UP); pongBalls[y].setContactedBound(); pts += 10; if (pts%100 == 0) addball = true; points = "Score: " + pts; } //now check the directions and move the ball accordingly if (pongBalls[y].getDirY() == PongBall.DirectionY.DOWN && pongBalls[y].getDirX() == PongBall.DirectionX.LEFT) { debuginfo = "Direction is DOWN and LEFT"; pongBalls[y].incY(); pongBalls[y].decX(); } if (pongBalls[y].getDirY() == PongBall.DirectionY.DOWN && pongBalls[y].getDirX() == PongBall.DirectionX.RIGHT) { debuginfo = "Direction is DOWN and RIGHT"; pongBalls[y].incY(); pongBalls[y].incX(); } if (pongBalls[y].getDirY() == PongBall.DirectionY.UP && pongBalls[y].getDirX() == PongBall.DirectionX.LEFT) { debuginfo = "Direction is UP and LEFT"; pongBalls[y].decY(); pongBalls[y].decX(); } if (pongBalls[y].getDirY() == PongBall.DirectionY.UP && pongBalls[y].getDirX() == PongBall.DirectionX.RIGHT) { debuginfo = "Direction is UP and RIGHT"; pongBalls[y].decY(); pongBalls[y].incX(); } }//end the for loop for each ball }//end for loopcount, while loopcount caused problems, such as the window not being filled in and freezing up... repaint(); } } private void movePaddle(MouseEvent evt) { mouseX = evt.getX(); if (mouseX < 50) mouseX = 50; if (mouseX > 1148) mouseX = 1148; repaint(); } public void paintComponent(Graphics g) { g.setColor(Color.BLACK); g.drawRect(50, 50, 1200, 600); //the outline of the box g.setColor(Color.WHITE); g.fillRect(51, 51, 1200-2, 600-2); //the background inside the box g.setColor(Color.LIGHT_GRAY); g.fillRect(0, 10, getWidth(), 20); //the background for the string info g.fillRect(0, 700, getWidth(), 20); g.setColor(Color.BLACK); g.drawString(debuginfo, 25, 25); // maybe remove this later... g.drawString(debuginfo2, 200, 25); g.drawString(debuginfo3, 900, 25); g.drawString(livesremaining, 400, 25); g.drawString(points, getWidth()/2, 25); //players score at the top of the window //END DEBUG INFO /*The rest of the paintComponent method describes the behaviors of each ball, and the paddle*/ if (!ballinmotion) { //at the start of the program pongBalls[0] = new PongBall(); if (pongBalls[0] instanceof PongBall) { i++; //so the iterator when adding balls based on score is used, it doesnt overlap the starting ball. debuginfo3 = "ball 0 spawned from ballinmotion check at first run through of paintComponent method"; } randomstart = (int)(Math.floor(Math.random() * 4 + 1)); //random starting ballinmotion = true; } for (int drawballs = 0, spacer = 0; drawballs < lives-1; drawballs++, spacer+=25) { g.setColor(Color.BLUE); g.fillOval((getWidth()/2)-((lives-1)*25)+spacer, 700, 14, 14); } if (mouseMoved) { g.setColor(Color.RED) ; g.fillRect(mouseX+1, 500, 100, 25); //the paddle } if (lives>0) { //if the user hasn't lost...s for (int x = 0; x < pongBalls.length; x++) { //draw all the balls in their current positions g.setColor(Color.BLACK); [COLOR="Red"][B]g.fillOval(pongBalls[x].getX(), pongBalls[x].getY(), 14, 14); //generates null ptr exception...[/B][/COLOR] } livesremaining = "Lives remaining: " + (lives-1); } if (redrawball == true) { //draw a new replacement ball in the middle pongBalls[balltodraw].setX(getWidth()/2); pongBalls[balltodraw].setY(getHeight()/2); redrawball = false; } if (addball && i <= 5) { pongBalls[i] = new PongBall(); i++; if (pongBalls[i-1] instanceof PongBall) { System.out.println("pongBalls " + (i-1) + "spawned"); debuginfo3 = "Ball " + (i-1) + "spawned using addball check"; } addball = false; } } private class MouseHandler implements MouseListener, MouseMotionListener { public void mousePressed(MouseEvent evt) { } public void mouseReleased(MouseEvent evt) { } public void mouseClicked(MouseEvent evt) { } public void mouseEntered(MouseEvent evt) { } public void mouseExited(MouseEvent evt) { } public void mouseMoved(MouseEvent evt) { movePaddle(evt); mouseMoved = true; } public void mouseDragged(MouseEvent evt) { } } // end nested class MouseHandler }
I instantiate pongBalls[0] the first time through the paintComponent() method, before any pongBalls object needs to be/is accessed. My understanding is that this ensures that the accesses I make inside my 'for' loops will succeed by accessing the 0'th element of the pongBalls object array (terminology?)Java Code:@SuppressWarnings("serial") public class PongBall extends PongPanel { public PongBall() { //constructor, start the ball in the middle ballX = getWidth()/2; ballY = getHeight()/2; } private int ballX; private int ballY; private boolean hitBound = false; public enum DirectionY {UP, DOWN}; public enum DirectionX {LEFT, RIGHT}; private DirectionY directionY; private DirectionX directionX; public int getX() {return ballX;}; public void incX() {ballX++;}; public void decX() {ballX--;}; public void setX(int newX) {ballX = newX;}; public int getY() {return ballY;}; public void incY() {ballY++;}; public void decY() {ballY--;}; public void setY(int newY) {ballY = newY;}; public DirectionX getDirX() {return directionX;}; public DirectionY getDirY() {return directionY;}; public void setDirX(DirectionX newDirX) {directionX = newDirX;}; public void setDirY(DirectionY newDirY) {directionY = newDirY;}; public boolean hasContactedBound() {return hitBound;}; public void setContactedBound() {hitBound = true;}; }
I instantiate more pongBalls when the addball boolean variable is true, which is triggered whenever the users score reaches a multiple of 100. Here is the bit of code that does the extra ball adding:
The line of code that throws the exception is:Java Code:if (addball && i <= 5) { pongBalls[i] = new PongBall(); i++; if (pongBalls[i-1] instanceof PongBall) { System.out.println("pongBalls " + (i-1) + "spawned"); debuginfo3 = "Ball " + (i-1) + "spawned using addball check"; } addball = false; }
When I add the line:Java Code:g.fillOval(pongBalls[x].getX(), pongBalls[x].getY(), 14, 14); //generates null ptr exception...
before the line that throws the exception, the following is printed:Java Code:System.out.println(pongBalls[x]);
PongBall[,0,0,0x0,invalid,layout=java.awt.FlowLayout,alignm entX=0.0,alignmentY=0.0,border=,flags=9,maximumSiz e=,minimumSize=,preferredSize=]
null
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at PongPanel.paintComponent(PongPanel.java:202)
at javax.swing.JComponent.paint(JComponent.java:1029)
at javax.swing.JComponent.paintChildren(JComponent.ja va:864)
at javax.swing.JComponent.paint(JComponent.java:1038)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:5 67)
at javax.swing.JComponent.paintChildren(JComponent.ja va:864)
at javax.swing.JComponent.paintToOffscreen(JComponent .java:5131)
at javax.swing.RepaintManager$PaintManager.paintDoubl eBuffered(RepaintManager.java:1475)
at javax.swing.RepaintManager$PaintManager.paint(Repa intManager.java:1406)
at javax.swing.RepaintManager.paint(RepaintManager.ja va:1220)
at javax.swing.JComponent.paint(JComponent.java:1015)
at java.awt.GraphicsCallback$PaintCallback.run(Graphi csCallback.java:21)
at sun.awt.SunGraphicsCallback.runOneComponent(SunGra phicsCallback.java:60)
at sun.awt.SunGraphicsCallback.runComponents(SunGraph icsCallback.java:97)
at java.awt.Container.paint(Container.java:1780)
at javax.swing.RepaintManager.paintDirtyRegions(Repai ntManager.java:814)
at javax.swing.RepaintManager.paintDirtyRegions(Repai ntManager.java:714)
at javax.swing.RepaintManager.seqPaintDirtyRegions(Re paintManager.java:694)
at javax.swing.SystemEventQueueUtilities$ComponentWor kRequest.run(SystemEventQueueUtilities.java:128)
at java.awt.event.InvocationEvent.dispatch(Invocation Event.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java: 597)
at java.awt.EventDispatchThread.pumpOneEventForFilter s(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(E ventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarch y(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispa tchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispa tchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThre ad.java:122)
...
...Last edited by DCC1; 07-10-2009 at 04:00 AM.
- 07-10-2009, 04:54 AM #4
How do you create pongBalls[]?
If you start off with only one ball and pongBalls is of length five, then you are going to get a null pointer exception because pongBalls[1-4] are all null.
-
Yep, you're trying to use PongBalls before you've initialized them. You're also trying to create PongBall objects and do program logic in the paintComponent method, and that's a bad idea.
- 07-10-2009, 06:59 PM #6
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
Okay, I have read both replies and attemmpted to change the way in which I instantiate the pongBalls. I have also tried to migrate some of the logic and all of the instantiation out of the paintComponent method and into the actionPerformed() method of the moveBall class. Thanks for that extra bit of advice.
I still have a NullPointerException, however:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at PongPanel.paintComponent(PongPanel.java:207)
at javax.swing.JComponent.paint(JComponent.java:1029)
at javax.swing.JComponent.paintChildren(JComponent.ja va:864)
at javax.swing.JComponent.paint(JComponent.java:1038)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:5 67)
at javax.swing.JComponent.paintChildren(JComponent.ja va:864)
at javax.swing.JComponent.paintToOffscreen(JComponent .java:5131)
at javax.swing.RepaintManager$PaintManager.paintDoubl eBuffered(RepaintManager.java:1475)
at javax.swing.RepaintManager$PaintManager.paint(Repa intManager.java:1406)
at javax.swing.RepaintManager.paint(RepaintManager.ja va:1220)
null
null
at javax.swing.JComponent.paint(JComponent.java:1015)
My revised source code for the PongPanel class is here:
I do my new instantiation here:Java Code:import java.awt.*; import java.awt.event.*; import javax.swing.JPanel; import javax.swing.Timer; @SuppressWarnings("serial") public class PongPanel extends JPanel { public PongPanel() { //constructor MouseHandler listener = new MouseHandler(); addMouseListener(listener); addMouseMotionListener(listener); moveBall action = new moveBall(); Timer timer = new Timer(10, action); timer.setInitialDelay(2000); //2 second initial delay timer.start(); } private int mouseX; private int rightbound = 1235; private int leftbound = 50; private int bottombound = 635; private int topbound = 50; private int i = 0; //iterator for array of objects private PongBall[] pongBalls = new PongBall[5]; private int lives = 6; private int pts = 0; private int loopcount = 0; private int randomstart; private int balltodraw; private int ballsToDraw = 0; private String debuginfo = "no direction yet..."; private String debuginfo2 = "no case executed yet..."; private String debuginfo3 = "no ball spawned yet..."; private String livesremaining = ""; private String points = "Score: " + pts; private boolean redrawball = true; private boolean ballinmotion = false; private boolean addball = false; private boolean init = false; public class moveBall implements ActionListener { public void actionPerformed(ActionEvent evt) { if (lives == 0) { debuginfo = "Game Over"; return; } if (!init) { for (int numballs = 0; numballs < 5; numballs++) { //initialize numballs pongBalls[numballs] = new PongBall(); } System.out.println(pongBalls[0]); init = true; } if (!ballinmotion) { //at the start of the program ballsToDraw++; randomstart = (int)(Math.floor(Math.random() * 4 + 1)); //random starting ballinmotion = true; } if (redrawball == true) { //draw a new replacement ball in the middle pongBalls[balltodraw].setX(getWidth()/2); pongBalls[balltodraw].setY(getHeight()/2); redrawball = false; } if (addball && i <= 5) { pongBalls[i] = new PongBall(); i++; if (pongBalls[i-1] instanceof PongBall) { System.out.println("pongBalls " + (i-1) + "spawned"); debuginfo3 = "Ball " + (i-1) + "spawned using addball check"; } addball = false; } //iterate through the balls for (int y = 0; y < pongBalls.length; y++) { if (!pongBalls[y].hasContactedBound()) { switch(randomstart) { case 1: debuginfo2 = "case 1 executed... for ball " + y; pongBalls[y].setDirY(PongBall.DirectionY.DOWN); pongBalls[y].setDirX(PongBall.DirectionX.LEFT); case 2: debuginfo2 = "case 2 executed... for ball " + y; pongBalls[y].setDirY(PongBall.DirectionY.DOWN); pongBalls[y].setDirX(PongBall.DirectionX.RIGHT); case 3: debuginfo2 = "case 3 executed... for ball " + y; pongBalls[y].setDirY(PongBall.DirectionY.UP); pongBalls[y].setDirX(PongBall.DirectionX.LEFT); case 4: debuginfo2 = "case 4 executed... for ball " + y; pongBalls[y].setDirY(PongBall.DirectionY.UP); pongBalls[y].setDirX(PongBall.DirectionX.RIGHT); } } //now determine the direction based on if the ball has hit a bound or paddle... for (loopcount = 0; loopcount < 4; loopcount++) { //for (int y = 0; y < pongBalls.length; y++) { if (pongBalls[y].getX() == rightbound) { pongBalls[y].setDirX(PongBall.DirectionX.LEFT); pongBalls[y].setContactedBound(); } if (pongBalls[y].getX() == leftbound) { pongBalls[y].setDirX(PongBall.DirectionX.RIGHT); pongBalls[y].setContactedBound(); } if (pongBalls[y].getY() == topbound) { pongBalls[y].setDirY(PongBall.DirectionY.DOWN); pongBalls[y].setContactedBound(); } if (pongBalls[y].getY() == bottombound) { //user fails pongBalls[y].setContactedBound(); lives--; //take away a life. livesremaining = "Lives remaining: " + (lives-1); redrawball = true; //redraw a ball balltodraw = y; //need to also set a delay for the timer, how to do this? } if ((pongBalls[y].getX() >= mouseX-5 && pongBalls[y].getX() <= mouseX+101) && (pongBalls[y].getY() == 485) && pongBalls[y].getDirY() == PongBall.DirectionY.DOWN) { //if the ball hits the //paddle on the way down... pongBalls[y].setDirY(PongBall.DirectionY.UP); pongBalls[y].setContactedBound(); pts += 10; if (pts%100 == 0) addball = true; points = "Score: " + pts; } //now check the directions and move the ball accordingly if (pongBalls[y].getDirY() == PongBall.DirectionY.DOWN && pongBalls[y].getDirX() == PongBall.DirectionX.LEFT) { debuginfo = "Direction is DOWN and LEFT"; pongBalls[y].incY(); pongBalls[y].decX(); } if (pongBalls[y].getDirY() == PongBall.DirectionY.DOWN && pongBalls[y].getDirX() == PongBall.DirectionX.RIGHT) { debuginfo = "Direction is DOWN and RIGHT"; pongBalls[y].incY(); pongBalls[y].incX(); } if (pongBalls[y].getDirY() == PongBall.DirectionY.UP && pongBalls[y].getDirX() == PongBall.DirectionX.LEFT) { debuginfo = "Direction is UP and LEFT"; pongBalls[y].decY(); pongBalls[y].decX(); } if (pongBalls[y].getDirY() == PongBall.DirectionY.UP && pongBalls[y].getDirX() == PongBall.DirectionX.RIGHT) { debuginfo = "Direction is UP and RIGHT"; pongBalls[y].decY(); pongBalls[y].incX(); } }//end the for loop for each ball }//end for loopcount, while loopcount caused problems, such as the window not being filled in and freezing up... repaint(); } } private void movePaddle(MouseEvent evt) { mouseX = evt.getX(); if (mouseX < 50) mouseX = 50; if (mouseX > 1148) mouseX = 1148; repaint(); } public void paintComponent(Graphics g) { g.setColor(Color.BLACK); g.drawRect(50, 50, 1200, 600); //the outline of the box g.setColor(Color.WHITE); g.fillRect(51, 51, 1200-2, 600-2); //the background inside the box g.setColor(Color.LIGHT_GRAY); g.fillRect(0, 10, getWidth(), 20); //the background for the string info g.fillRect(0, 700, getWidth(), 20); g.setColor(Color.BLACK); g.drawString(debuginfo, 25, 25); // maybe remove this later... g.drawString(debuginfo2, 200, 25); g.drawString(debuginfo3, 900, 25); g.drawString(livesremaining, 400, 25); g.drawString(points, getWidth()/2, 25); //players score at the top of the window //END DEBUG INFO g.setColor(Color.BLUE); for (int drawballs = 0, spacer = 0; drawballs < lives-1; drawballs++, spacer+=25) { g.fillOval((getWidth()/2)-((lives-1)*25)+spacer, 700, 14, 14); } if (lives>0) { //if the user hasn't lost... g.setColor(Color.BLACK); for (int x = 0; x < pongBalls.length; x++) { //draw all the balls in their current positions System.out.println(pongBalls[x]); //for debugging g.fillOval(pongBalls[x].getX(), pongBalls[x].getY(), 14, 14); } } } private class MouseHandler implements MouseListener, MouseMotionListener { public void mousePressed(MouseEvent evt) { } public void mouseReleased(MouseEvent evt) { } public void mouseClicked(MouseEvent evt) { } public void mouseEntered(MouseEvent evt) { } public void mouseExited(MouseEvent evt) { } public void mouseMoved(MouseEvent evt) { movePaddle(evt); } public void mouseDragged(MouseEvent evt) { } } // end nested class MouseHandler }
Does this properly initialize pongBalls[0,1,2,3,4,5]?Java Code:if (!init) { for (int numballs = 0; numballs < 5; numballs++) { //initialize numballs pongBalls[numballs] = new PongBall(); } System.out.println(pongBalls[0]); init = true; }
The System.out.println prints 'null', as expected given the exception at the same line of code as before:< --EDIT-->Java Code:g.fillOval(pongBalls[x].getX(), pongBalls[x].getY(), 14, 14);
I am thinking this may have something to do with something I read in a tutorial, that the paintComponent() method is called first/immediately on program execution, which will, in this case, result in pongBalls[] access attempts before any instantiation can be done... Could this be what is causing the problem? How might I go about forcing initialization before doing any drawing? (I have tried putting the initialization of pongBalls in the constructor of the PongPanel class, my compiler complains that I am doing something wrong.
</ --EDIT-->
Again, I appreciate the help... Hopefully this isn't something I've just noobishly overlooked time and time again... although it probably is.Last edited by DCC1; 07-10-2009 at 07:03 PM.
-
I can't get your code to compile. Is this the whole program?
- 07-11-2009, 12:20 AM #8
Senior Member
- Join Date
- Mar 2009
- Posts
- 552
- Rep Power
- 5
I think paintComponent() is actually called by the JComponent constructor. Therefore, non-static code blocks SHOULD work, as they are called by the class constructor before any super-constructor calls. I could be wrong, however...
I did not try to compile your code, as Fubarable said it did not compile. However, If you do post your code, attaching it all in a zip file is probably preferable.If the above doesn't make sense to you, ignore it, but remember it - might be useful!
And if you just randomly taught yourself to program, well... you're just like me!
- 07-11-2009, 05:03 AM #9
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
Okay, I have put all three files of my source code into a zip 'pong.zip'
There should be three files:
PongApp.java (to run the program as an application, not applet)
PongBall.java (the PongBall class that describes the properties and behavior of the ball)
PongPanel.java (describes the paintComponent() and moveBall() methods, (and some others that deal with mouse listeners and timers) and where the instantiation of the PongBall class is done.
I compiled these using Eclipse, in the 'default package'.
I appreciate your time in compiling this to help. Let me know if there is anything else I can do to make this clearer.
- 07-11-2009, 05:15 AM #10
Senior Member
- Join Date
- Dec 2008
- Location
- Hong Kong
- Posts
- 473
- Rep Power
- 5
you initialize numballs when action performed,
before user perform action, all balls are nullLast edited by mtyoung; 07-11-2009 at 05:19 AM.
- 07-11-2009, 07:05 AM #11
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
In the constructor of the PongPanel class, which is called automatically when the program executes, is the following code:
The actionPerformed() method, which contains the initialization for PongBall, should be called when timer.start() is executed, right? If this is the case, I would expect the PongBalls to be initialized there. If I am wrong, where should I be able to put the PongBall initialization so that the compiler won't complain, and to assure that PongBall will be initialized for pongBalls[0,1,2,3,4] before any access attempts?Java Code:... moveBall action = new moveBall(); Timer timer = new Timer(10, action); timer.setInitialDelay(2000); //2 second initial delay timer.start();
I have tried placing the initialization,,Java Code:for (int numballs = 0; numballs < 5; numballs++) { //initialize numballs pongBalls[numballs] = new PongBall(); }
in the constructor to my PongPanel class, but when I run the program, I get another error:
UIDefaults.getUI() failed: createUI() failed for PongBall[,0,0,0x0,invalid,layout=java.awt.FlowLayout,alignm entX=0.0,alignmentY=0.0,border=,flags=9,maximumSiz e=,minimumSize=,preferredSize=] java.lang.reflect.InvocationTargetException
java.lang.Error
at javax.swing.UIDefaults.getUIError(UIDefaults.java: 711)
at javax.swing.MultiUIDefaults.getUIError(MultiUIDefa ults.java:133)
at javax.swing.UIDefaults.getUI(UIDefaults.java:757)
at javax.swing.UIManager.getUI(UIManager.java:1017)
at javax.swing.JPanel.updateUI(JPanel.java:109)
at javax.swing.JPanel.<init>(JPanel.java:69)
at javax.swing.JPanel.<init>(JPanel.java:92)
at javax.swing.JPanel.<init>(JPanel.java:100)
at PongPanel.<init>(PongPanel.java:10)
...
...
The source code that generates this error is the same as that in the zip file, except that:
has been placed in the constructor of the PongPanel class and taken out of the actionPerformed() method of the moveBall class.Java Code:for (int numballs = 0; numballs < 5; numballs++) { //initialize numballs pongBalls[numballs] = new PongBall(); }
Am I not sure why putting the initialization in the constructor, which, at least to a noob such as myself seems like a good idea, causes a problem.
-
This has nothing to do with your NPE, but why does PongBall extend PongPanel? This seems a set up for a circular reference?
- 07-11-2009, 06:18 PM #13
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
The PongBall class extends the PongBall to get access to the getHeight() and getWidth() methods that pertain to the PongPanel class (dimensions of the window).
Is this not the correct way to do this? Might it make more sense to not extend PongPanel and not use those methods?
By circular reference, is that similar to a Singly Linked Circular List?
- 07-11-2009, 06:41 PM #14
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
After reading Fubarable's post regarding the extension of the PongPanel class in PongBall, I removed the extension and commented out the methods in the constructor of PongBall. The program no longer throws an exception. It might be important to note that this is after the initialization of PongBall's are done in the constructor of the PongPanel class. I am still interested in hearing about the circular reference situation, as it might be a better/more correct way to do this?
The program still behaves strangely, but I am confident that without the unexpected exceptions I will be able to work out the other details. Thanks for the time to read this and for the pointers.
-
The question you need to ask yourself is: is a PongBall a PongPanel? In other words does it fulfill an "is-a" relationship (google this term)? Answer: it does not. For example, a class Dog would fulfill an is-a relationship with an Animal class, but not with a DogHouse class, so Dog can extend Animal but should never extend DogHouse. Another important concept is that of the "has-a" relationship. DogHouse does fulfill a has-a relationship with Dog, and thus it can hold Dog objects. PongPanel likewise can fulfill has-a with PongBall and can hold these objects as fields of the class.
Point number two, making it subclass PongPanel wouldn't automatically give it the width and height since it is not the same object as the "true" PongPanel. Inheritance is not the way to pass this information.
And final point: PongBall doesn't even need to know this information. Does a physical ball know where the ground is? Nope, it only knows when it collides with something. So give your PongBall class a boolean method contains(int x, int y), to see if a point is contained in the ball or not. That way the object that holds the balls can easily test for collisions.
preciselyIs this not the correct way to do this? Might it make more sense to not extend PongPanel and not use those methods?
Nope, I mean you have a PongPanel that contains PongBalls, and these subclass PongPanel, and this can contain PongBalls, and these subclass PongPanel...By circular reference, is that similar to a Singly Linked Circular List?
It can get downright ugly here.Last edited by Fubarable; 07-11-2009 at 09:14 PM.
- 07-12-2009, 04:00 AM #16
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
I see, and feel I have a better understanding of how this stuff works...
I see what is meant by the circular reference - didn't even realize that's what I was doing... I have removed the extension of PongPanel in the PongBall class, and am storing each PongBall's coordinates in the objects instantiated by PongBall. I am currently checking for collisions through the PongPanel class, that accesses the x and y coordinates of each ball and checks to see if they are the same as respective coordinates regarding the things I want it to 'bounce' off of, I.E. the paddle and walls.
I am now passing the information about the initial position of the ball to the constructor of PongBall from PongPanel, instead of using inheritance as you suggested, and this does seem much more reasonable/easy to understand. When drawing the PongBalls in the PongPanel class, I access the PongBalls X and Y coordinates and print the ball with those coordinates to the screen via the paintComponent() method in PongPanel - I think a little different than the method you suggested - but I will certainly your idea.
About the boolean contains(int x, int y) - this method would be called from the PongPanel class on one of any of the PongBall objects, and this method would check to see if the values I pass by reference are the same as the current PongBall object's ballX and ballY coordinates? This seems like it should work.
Thanks for the help. I do appreciate it and will try to help others on the forum if it's something I can help with. I hope not to be a 'leecher', but fear that until I get to know more about more complex concepts I won't be much help to many, but you never know.Last edited by DCC1; 07-12-2009 at 04:13 AM.
- 07-12-2009, 05:20 AM #17
Member
- Join Date
- Apr 2009
- Location
- Brisbane
- Posts
- 86
- Rep Power
- 0
regarding the Ball.contains(int x, int y) suggestion... Ummm... The below code isn't "best practice", but it works...
My move methods primary job is to move the ball into position for it's next paint... and (here's the "not best practice" part) it also has the "side effect" of setting a couple of boolean attributes (hitWall, and isOutOfBounds) which I can query later.
In the swing-timer you move the ball, and then ask it "what happened"...Java Code:private class Ball { .... void move() { hitWall = false; if ( x<=Box.LEFT || x+SIZE>=Box.RIGHT ) { hitWall = true; xDirection *= -1; // u-turn } if ( y <= Box.TOP ) { hitWall = true; yDirection *= -1; // u-turn } else if (y+SIZE >= Box.BOTTOM) { isOutOfBounds = true; } x += xDirection * speed; y += yDirection * speed; } .... }
Also see the paddle.hit(ball) method. With 20-20 hindsight I think it would be a better if both Box and Paddle extended a new Rectangle, and give the Ball a within(Rectangle rect) method.Java Code:for (Ball ball : balls) { ball.move(); if ( ball.hitWall ) { ....
Here's the full code ...
Cheers. Keith.Java Code:package forums; import java.util.List; import java.util.ArrayList; import java.util.Random; import java.awt.Graphics; import java.awt.Color; import java.awt.Dimension; //import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseEvent; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.WindowListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.JOptionPane; public class DccPongPanel extends JPanel { private static final long serialVersionUID = 1L; private static final Random RANDOM = new Random(); private static final java.awt.Toolkit TOOLKIT = java.awt.Toolkit.getDefaultToolkit(); private static final Dimension PREFERRED_SIZE = new Dimension(Box.WIDTH+100, Box.HEIGHT+100); private static final int MAX_SPEED = 5; private static final int REFRESH_RATE = 1000/76; private static final int MAX_BALLS = 6; private static final int NUM_LIVES = 12; private static JFrame frame; private final Box box = new Box(); private final ScoreBoard scoreBoard = new ScoreBoard(); private final Paddle paddle = new Paddle(); private final List<Ball> balls = new ArrayList<Ball>(); private int lives = NUM_LIVES; private int score = 0; private String scoreString = "Score: "+score; private Timer timer; public DccPongPanel() { addMouseMotionListener(new MouseHandler()); WindowHandler windowHandler = new WindowHandler(); frame.addWindowListener(windowHandler); frame.addWindowFocusListener(windowHandler); frame.addWindowStateListener(windowHandler); DEBUG("add Ball[0]"); balls.add(new Ball(Ball.DOWN, 2, 0)); timer = new Timer(REFRESH_RATE, new Mover()); timer.setInitialDelay(500); // half-second delay. timer.start(); } public Dimension getPreferredSize() { return this.PREFERRED_SIZE; } public void paintComponent(Graphics g) { super.paintComponent(g); box.paint(g); scoreBoard.paint(g); synchronized(balls) { for (Ball ball : balls) { ball.paint(g); } } paddle.paint(g); } public static void DEBUG(String message) { if (true) { System.err.println("DEBUG: "+message); } } private void movePaddle(final int x) { if (x < Box.LEFT) { paddle.x = Box.LEFT; } else if ( x > Box.RIGHT-Paddle.WIDTH ) { paddle.x = Box.RIGHT-Paddle.WIDTH; } else { paddle.x = x; } repaint(); } private class Mover implements ActionListener { public void actionPerformed(ActionEvent evt) { if (lives == 0) { gameOver(); return; } synchronized(balls) { boolean addBall = false; for (Ball ball : balls) { ball.move(); if ( ball.hitWall ) { increaseScore(); addBall |= score==20||score==50||score%100==0; } else if ( paddle.hit(ball) ) { ball.yDirection = -1; // UP increaseScore(); addBall |= score==20||score==50||score%100==0; ball.speedUp(); } else if ( ball.isOutOfBounds ) { DEBUG("lives--"); ball.reset(); lives--; } } if (balls.size()<MAX_BALLS && addBall) { DEBUG("add Ball["+balls.size()+"]"); balls.add(new Ball(Ball.UP, 1, balls.size())); } } //end-synchronized repaint(); } private void gameOver() { DEBUG("Game Over"); timer.stop(); JOptionPane.showMessageDialog(frame, "That's a bit deceptive.", "Game Over", JOptionPane.ERROR_MESSAGE); score=0; lives=NUM_LIVES; balls.clear(); balls.add(new Ball(Ball.DOWN, 2, 0)); timer.start(); } } private void increaseScore() { score += 10; scoreString = "Score: "+score; } private class MouseHandler implements MouseMotionListener { public void mouseMoved(MouseEvent evt) { movePaddle(evt.getX()); } public void mouseDragged(MouseEvent evt) { } } private class WindowHandler extends WindowAdapter { public void windowDeactivated(WindowEvent e) { timer.stop(); } public void windowActivated(WindowEvent e) { timer.start(); } public void windowIconified(WindowEvent e) { timer.stop(); } public void windowDeiconified(WindowEvent e) { timer.start(); } } private class Box { static final int WIDTH = 900; static final int HEIGHT = 500; static final int TOP = 50; static final int LEFT = 50; static final int BOTTOM = TOP+HEIGHT; static final int RIGHT = LEFT+WIDTH; static final int MIDX = (RIGHT-LEFT)/2; static final int MIDY = (BOTTOM-TOP)/2; void paint(Graphics g) { g.setColor(Color.BLACK); g.drawRect(LEFT, TOP, WIDTH, HEIGHT); // outline g.setColor(Color.WHITE); g.fillRect(LEFT+1, TOP+1, WIDTH-2, HEIGHT-2); // shadow } } private class Paddle { static final int THICKNESS = 25; static final int WIDTH = 100; static final int Y = Box.BOTTOM-THICKNESS; int x = Box.MIDX; boolean hit(Ball ball) { return ball.x>=x && ball.x+Ball.SIZE<=x+WIDTH && ball.y+Ball.SIZE>=Y && ball.yDirection==Ball.DOWN; } void paint(Graphics g) { g.setColor(Color.RED) ; g.fillRect(x+1, Y, WIDTH, THICKNESS); } } private class Ball { static final int SIZE=15, DOWN=1, UP=-1, LEFT=-1, RIGHT=1; int x, y, xDirection, yDirection, id; private volatile int speed; volatile boolean isOutOfBounds, hitWall;; Ball(int yDirection, int speed, int id) { reset(); this.yDirection = yDirection==UP ? UP : DOWN; this.speed = speed>=1&&speed<=MAX_SPEED ? speed : 1; this.id = id; } void reset() { x = Box.MIDX; y = Box.MIDY; xDirection = RANDOM.nextBoolean() ? LEFT : RIGHT; yDirection = UP; speed = 1; isOutOfBounds = hitWall = false; } void move() { hitWall = false; if ( x<=Box.LEFT || x+SIZE>=Box.RIGHT ) { hitWall = true; xDirection *= -1; // u-turn } if ( y <= Box.TOP ) { hitWall = true; yDirection *= -1; // u-turn } else if (y+SIZE >= Box.BOTTOM) { isOutOfBounds = true; } x += xDirection * speed; y += yDirection * speed; } void speedUp() { if(speed<MAX_SPEED) { speed++; //DEBUG("Ball["+id+"].speed="+speed); } } void paint(Graphics g) { g.setColor(Color.BLACK); g.fillOval(x, y, SIZE-1, SIZE-1); } } private class ScoreBoard { private static final int TOP = 10; private static final int HEIGHT = 20; void paint(Graphics g) { g.setColor(Color.LIGHT_GRAY); g.fillRect(Box.LEFT, TOP, Box.WIDTH, HEIGHT); // background g.setColor(Color.BLACK); g.drawString(scoreString, Box.MIDX, TOP+15); // score g.setColor(Color.BLUE); for (int i=0; i<lives; i++) { // lives g.fillRect(Box.LEFT+10+i*12, TOP+6, 8, 8); } } } public static void buildAndShowGUI(){ frame = new JFrame("DCC Pong - Rocks my world!"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setContentPane(new DccPongPanel()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater( new Runnable() { public void run() { buildAndShowGUI(); } } ); } }
- 07-12-2009, 06:42 PM #18
Member
- Join Date
- Jul 2009
- Posts
- 10
- Rep Power
- 0
Very impressed - everything I was trying to accomplish works perfectly right there.
I have a question regarding the pain() functions defined in some of the classes - how are these functions called? Are they called separately from one another? Until now, I only knew how to use the same paintComponent() command to redraw the entire screen at once - it seems as though here, each item that needs to be drawn on the screen (the paddle, the ball(s), the box, scoreboard etc). Does the paintComponent() method which calls each object's paint() method get called automaticaly itself every REFRESH_RATE interval?
Some other things like synchronized I will look up myself and learn about, but I am still not 100% clear on the paintComponent() situation... In the meantime I will mark the post as 'resolved' since my original problem - the exception - has been resolved.
Similar Threads
-
.class expected
By dre in forum New To JavaReplies: 6Last Post: 06-27-2009, 06:01 PM -
Class Expected error
By Radman23 in forum New To JavaReplies: 11Last Post: 01-14-2009, 04:12 AM -
'class' or 'interface' expected
By denisdoherty in forum New To JavaReplies: 23Last Post: 04-22-2008, 06:13 PM -
class or interface expected -compile err
By ravi503 in forum Java ServletReplies: 1Last Post: 03-26-2008, 11:45 AM -
illegal start of expression & class, interface, or enum expected
By silverq_82 in forum New To JavaReplies: 9Last Post: 08-08-2007, 07:16 PM


LinkBack URL
About LinkBacks
Reply With Quote

Bookmarks