Thanks for the reply. My full source code for PongPanel.java is as follows:
|
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);
g.fillOval(pongBalls[x].getX(), pongBalls[x].getY(), 14, 14); //generates null ptr exception...
}
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
} |
The full source code for the PongBall class is as follows:
|
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 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?)
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:
|
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;
} |
The line of code that throws the exception is:
|
Code:
|
g.fillOval(pongBalls[x].getX(), pongBalls[x].getY(), 14, 14); //generates null ptr exception... |
When I add the line:
|
Code:
|
System.out.println(pongBalls[x]); |
before the line that throws the exception, the following is printed:
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)
...
...