Hello,
I made a simple game here and I get problem when gameOver() method is called. What it does is:
1. Stop the timers
2. Calculate player statistics
3. Print "GAME OVER" in the middle of the screen
4. Sleep the program for 3000ms
5. fill the screen with black rectangle and draw a statistic on it.
The problem is that it doesn't print "GAME OVER" in the middle of the screen. Whenever the game is over, the game sleeps for 3000ms with the last scene of the game and after that pops the statistic. Can anybody tell me why it behaves so?
import java.awt.Container; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Dimension; import java.awt.BorderLayout; import java.awt.Image; import java.awt.Toolkit; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Point; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.ImageIcon; import javax.swing.Timer; class AlienGame extends JFrame { AlienGame(String title) { setTitle(title); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); setLocationRelativeTo(null); setSize(400, 300); Container c = getContentPane(); c.setLayout(new BorderLayout()); c.add(new Board(), BorderLayout.CENTER); } public static void main(String args[ ]) { AlienGame a = new AlienGame("Alien game 2010 (c)"); a.setVisible(true); } } class Board extends JPanel implements ActionListener { // VARIABLES Image craft; Image missile; Image alien; ImageIcon craftIcon; ImageIcon missileIcon; ImageIcon alienIcon; Timer timer; Timer alienTimer; Font scoreFont = new Font("Arial", Font.PLAIN, 10); Dimension craftDimension, alienDimension, missileDimension; ArrayList<Missile> missiles = new ArrayList<Missile>(); ArrayList<Aliens> aliens = new ArrayList<Aliens>(); int craftX; int craftY; int craftDX; int craftDY; int alienDX = 1; int missileDX = 6; int panelWidth; int panelHeight; int alienDelay = 5000; int score = 0; int totalAliens = 0; int missedAliens = 0; int totalMissiles = 0; int missedMissiles = 0; Point pointCraft; Rectangle rectangleCraft; final int DELAY = 10; boolean craftVisible = true; boolean alienVisible = true; Board() { setBackground(Color.BLACK); setFocusable(true); setDoubleBuffered(true); addKeyListener(new MovementHandler()); setImages(); timer = new Timer(DELAY, this); timer.start(); AlienListener al = new AlienListener(); alienTimer = new Timer(alienDelay, al); alienTimer.start(); craftX = 40; craftY = 60; } void setImages() { craftIcon = new ImageIcon(getClass().getResource("craft.png")); craft = craftIcon.getImage(); craftDimension = new Dimension(craftIcon.getIconWidth(), craftIcon.getIconHeight()); pointCraft = new Point(craftX, craftY); rectangleCraft = new Rectangle(pointCraft, craftDimension); missileIcon = new ImageIcon(getClass().getResource("missile.png")); missile = missileIcon.getImage(); missileDimension = new Dimension(missileIcon.getIconWidth(), missileIcon.getIconHeight()); alienIcon = new ImageIcon(getClass().getResource("alien.png")); alien = alienIcon.getImage(); alienDimension = new Dimension(alienIcon.getIconWidth(), alienIcon.getIconHeight()); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; Dimension d = getSize(); panelWidth = (int) d.getWidth(); panelHeight = (int) d.getHeight(); g.setColor(Color.WHITE); g.drawString("Score: " + score, 5, 10); if(craftVisible) { // craft drawings g2.drawImage(craft, craftX, craftY, this); rectangleCraft.setLocation(craftX, craftY); // missile drawings for(int i = 0; i < missiles.size(); i++) { Missile m = (Missile) missiles.get(i); if(m.visible() && m.getX() < panelWidth) { g2.drawImage(missile, m.getX(), m.getY(), this); m.setRectangle(); } if(m.getX() > panelWidth) { missedMissiles++; missiles.remove(i); } else m.setX(missileDX); } // alien drawings for(int i = 0; i < aliens.size(); i++) { Aliens a = (Aliens) aliens.get(i); if(a.visible() && a.getX() >= 0) { g2.drawImage(alien, a.getX(), a.getY(), this); a.setRectangle(); } if(a.getX() < 0 || !a.visible()) { if(a.getX() < 0 && a.visible()) { missedAliens++; } aliens.remove(i); } else a.setX(alienDX); if(a.getRectangle().intersects(rectangleCraft)) craftVisible = false; } // check collision for(int i = 0; i < aliens.size(); i++) { for(int j = 0; j < missiles.size(); j++) { Missile m = missiles.get(j); Aliens a = aliens.get(i); if(aliens.get(i).getRectangle().intersects(missiles.get(j).getRectangle())) { m.setVisible(false); a.setVisible(false); score++; } } } } else gameOver(g); Toolkit.getDefaultToolkit().sync();//makes smooth controling g.dispose(); } void fire() { totalMissiles++; missiles.add(new Missile((int)(craftX + craftDimension.getWidth()), (int)(craftY + craftDimension.getHeight()/2), missileDimension)); } void gameOver(Graphics g) { Graphics g1 = g; // stops the timers timer.stop(); alienTimer.stop(); // statistic calculations totalAliens = missedAliens + score; int percentDestroyed; int destroyedMissiles; int percentAccuracy; double tempAliens; double tempAccuracy; if(score == totalAliens) percentDestroyed = 100; else if(score > 0) { tempAliens = 100 / totalAliens; percentDestroyed = (int) (tempAliens * score); } else percentDestroyed = 0; if(missedMissiles > 0) destroyedMissiles = totalMissiles - missedMissiles; else destroyedMissiles = 0; if(score == totalMissiles) percentAccuracy = 100; else if(score > 0) { tempAccuracy = 100 / totalMissiles; percentAccuracy = (int)(tempAccuracy * score); } else percentAccuracy = 0; // new variables declaration String s = "STATISTIC:"; String over = "GAME OVER"; String scoreString = "Score: " + score; String missedAliensString = "Aliens destroyed: " + score + "/" + totalAliens + " (" + percentDestroyed + "%)"; String accuracy = "Accuracy: " + score + "/" + totalMissiles + " (" + percentAccuracy + "%)"; Font fontLarge = new Font("Arial", Font.BOLD, 20); Font fontSmall = new Font("Arial", Font.ITALIC, 16); FontMetrics fmLarge = g1.getFontMetrics(); FontMetrics fmSmall = g1.getFontMetrics(); // printing "GAME OVER" g1.setFont(fontLarge); g1.setColor(Color.WHITE); g1.drawString(over, (panelWidth - fmLarge.stringWidth(over)) / 2, panelHeight / 2); // sleeping the program try { Thread.sleep(3000); } catch(Exception e) { e.printStackTrace(); } // drawing the statistic g1.setColor(Color.BLACK); g1.fillRect(0, 0, panelWidth, panelHeight); g1.setColor(Color.WHITE); g1.drawString(s, (panelWidth - fmLarge.stringWidth(s)) / 2, panelHeight / 3); g1.setFont(fontSmall); g1.drawString(scoreString, (panelWidth - fmSmall.stringWidth(scoreString)) / 2, panelHeight / 3 + 50); g1.drawString(missedAliensString, (panelWidth - fmSmall.stringWidth(missedAliensString)) / 2, panelHeight / 3 + 100); g1.drawString(accuracy, (panelWidth - fmSmall.stringWidth(accuracy)) / 2, panelHeight / 3 + 150); } public void actionPerformed(ActionEvent event) { if(craftVisible) { craftX += craftDX; craftY += craftDY; if(craftX < 1) craftX = 1; if(craftX > (int)(panelWidth - craftDimension.getWidth())) craftX = (int)(panelWidth - craftDimension.getWidth()); if(craftY < 1) craftY = 1; if(craftY > (int)(panelHeight - craftDimension.getHeight())) craftY = (int)(panelHeight - craftDimension.getHeight()); } repaint(); } ////// PRIVATE INNER CLASS FOR KeyAdapter //////// private class MovementHandler extends KeyAdapter { public void keyPressed(KeyEvent event) { int keycode = event.getKeyCode(); switch(keycode) { case(KeyEvent.VK_UP): craftDY = -2; break; case(KeyEvent.VK_DOWN): craftDY = 2; break; case(KeyEvent.VK_LEFT): craftDX = -2; break; case(KeyEvent.VK_RIGHT): craftDX = 2; break; case(KeyEvent.VK_SPACE): fire(); break; } } public void keyReleased(KeyEvent event) { int keycode = event.getKeyCode(); switch(keycode) { case(KeyEvent.VK_UP): craftDY = 0; break; case(KeyEvent.VK_DOWN): craftDY = 0; break; case(KeyEvent.VK_LEFT): craftDX = 0; break; case(KeyEvent.VK_RIGHT): craftDX = 0; break; } } } ////// PRIVATE INNER CLASS FOR ActionListener //////// class AlienListener implements ActionListener { public void actionPerformed(ActionEvent event) { Random r = new Random(); alienDelay = r.nextInt(3000) + 50; alienTimer.setDelay(alienDelay); int randomLoc = r.nextInt(266); aliens.add(new Aliens(panelWidth, randomLoc, alienDimension)); } } } class Missile { int x; int y; boolean missileVisible = true; Rectangle rectangleMissile; Point pointMissile; Missile(int x, int y, Dimension d) { this.x = x; this.y = y; pointMissile = new Point(x, y); rectangleMissile = new Rectangle(pointMissile, d); } void setX(int x) { this.x += x; } int getX() { return x; } int getY() { return y; } void setRectangle() { rectangleMissile.setLocation(x, y); } Rectangle getRectangle() { return rectangleMissile; } void setVisible(boolean v) { missileVisible = v; } boolean visible() { return missileVisible; } } class Aliens { boolean alienVisible = true; int x; int y; Point pointAlien; Rectangle rectangleAlien; Aliens(int x, int y, Dimension d) { this.x = x; this.y = y; pointAlien = new Point(x, y); rectangleAlien = new Rectangle(pointAlien, d); } void setX(int d) { x -= d; } public int getX() { return x; } public int getY() { return y; } void setRectangle() { rectangleAlien.setLocation(x, y); } Rectangle getRectangle() { return rectangleAlien; } void setVisible(boolean v) { alienVisible = v; } boolean visible() { return alienVisible; } }
************************************************** ************************************************** ****
EDIT: [SOLVED]
Solved it with adding a new timer in the end of the game which fires once after particular delay.
Thank you all for the advices in coding. I won't edit this code. I'll use them in the next game.
import java.awt.Container; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Dimension; import java.awt.BorderLayout; import java.awt.Image; import java.awt.Toolkit; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Point; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.ImageIcon; import javax.swing.Timer; class AlienGame extends JFrame { AlienGame(String title) { setTitle(title); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(false); setLocationRelativeTo(null); setSize(400, 300); Container c = getContentPane(); c.setLayout(new BorderLayout()); c.add(new Board(), BorderLayout.CENTER); } public static void main(String args[ ]) { AlienGame a = new AlienGame("Alien game 2010 (c)"); a.setVisible(true); } } class Board extends JPanel implements ActionListener { // VARIABLES Image craft; Image missile; Image alien; ImageIcon craftIcon; ImageIcon missileIcon; ImageIcon alienIcon; Timer timer; Timer alienTimer; Font scoreFont = new Font("Arial", Font.PLAIN, 10); Dimension craftDimension, alienDimension, missileDimension; ArrayList<Missile> missiles = new ArrayList<Missile>(); ArrayList<Aliens> aliens = new ArrayList<Aliens>(); int craftX; int craftY; int craftDX; int craftDY; int alienDX = 1; int missileDX = 6; int panelWidth; int panelHeight; int alienDelay = 5000; int score = 0; int totalAliens = 0; int missedAliens = 0; int totalMissiles = 0; int missedMissiles = 0; Point pointCraft; Rectangle rectangleCraft; final int DELAY = 10; boolean craftVisible = true; boolean alienVisible = true; boolean statistic = false; Board() { setBackground(Color.BLACK); setFocusable(true); setDoubleBuffered(true); addKeyListener(new MovementHandler()); setImages(); timer = new Timer(DELAY, this); timer.start(); AlienListener al = new AlienListener(); alienTimer = new Timer(alienDelay, al); alienTimer.start(); craftX = 40; craftY = 60; } void setImages() { craftIcon = new ImageIcon(getClass().getResource("craft.png")); craft = craftIcon.getImage(); craftDimension = new Dimension(craftIcon.getIconWidth(), craftIcon.getIconHeight()); pointCraft = new Point(craftX, craftY); rectangleCraft = new Rectangle(pointCraft, craftDimension); missileIcon = new ImageIcon(getClass().getResource("missile.png")); missile = missileIcon.getImage(); missileDimension = new Dimension(missileIcon.getIconWidth(), missileIcon.getIconHeight()); alienIcon = new ImageIcon(getClass().getResource("alien.png")); alien = alienIcon.getImage(); alienDimension = new Dimension(alienIcon.getIconWidth(), alienIcon.getIconHeight()); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; Dimension d = getSize(); panelWidth = (int) d.getWidth(); panelHeight = (int) d.getHeight(); g.setColor(Color.WHITE); g.drawString("Score: " + score, 5, 10); if(craftVisible) { // craft drawings g2.drawImage(craft, craftX, craftY, this); rectangleCraft.setLocation(craftX, craftY); // missile drawings for(int i = 0; i < missiles.size(); i++) { Missile m = (Missile) missiles.get(i); if(m.visible() && m.getX() < panelWidth) { g2.drawImage(missile, m.getX(), m.getY(), this); m.setRectangle(); } if(m.getX() > panelWidth) { missedMissiles++; missiles.remove(i); } else m.setX(missileDX); } // alien drawings for(int i = 0; i < aliens.size(); i++) { Aliens a = (Aliens) aliens.get(i); if(a.visible() && a.getX() >= 0) { g2.drawImage(alien, a.getX(), a.getY(), this); a.setRectangle(); } if(a.getX() < 0 || !a.visible()) { if(a.getX() < 0 && a.visible()) { missedAliens++; } aliens.remove(i); } else a.setX(alienDX); if(a.getRectangle().intersects(rectangleCraft)) craftVisible = false; } // check collision for(int i = 0; i < aliens.size(); i++) { for(int j = 0; j < missiles.size(); j++) { Missile m = missiles.get(j); Aliens a = aliens.get(i); if(aliens.get(i).getRectangle().intersects(missiles.get(j).getRectangle())) { m.setVisible(false); a.setVisible(false); score++; } } } } else { gameOver(g); Timer t = new Timer(4000, new Statistic()); t.setRepeats(false); t.start(); } if(statistic) { Font fontLarge = new Font("Arial", Font.BOLD+Font.ITALIC, 20); g.setFont(fontLarge); FontMetrics fmLarge = g.getFontMetrics(); totalAliens = missedAliens + score; int percentDestroyed; int destroyedMissiles; int percentAccuracy; double tempAliens; double tempAccuracy; if(score == totalAliens) percentDestroyed = 100; else if(score > 0) { tempAliens = 100 / totalAliens; percentDestroyed = (int) (tempAliens * score); } else percentDestroyed = 0; if(missedMissiles > 0) destroyedMissiles = totalMissiles - missedMissiles; else destroyedMissiles = 0; if(score == totalMissiles) percentAccuracy = 100; else if(score > 0) { tempAccuracy = 100 / totalMissiles; percentAccuracy = (int)(tempAccuracy * score); } else percentAccuracy = 0; String s = "STATISTIC:"; String scoreString = "Score: " + score; String missedAliensString = "Aliens destroyed: " + score + "/" + totalAliens + " (" + percentDestroyed + "%)"; String accuracy = "Accuracy: " + score + "/" + totalMissiles + " (" + percentAccuracy + "%)"; Font fontSmall = new Font("Arial", Font.ITALIC, 16); g.setFont(fontSmall); FontMetrics fmSmall = g.getFontMetrics(); g.setColor(Color.BLACK); g.fillRect(0, 0, panelWidth, panelHeight); g.setColor(Color.WHITE); g.setFont(fontLarge); g.drawString(s, (panelWidth - fmLarge.stringWidth(s)) / 2, panelHeight / 3); g.setFont(fontSmall); g.drawString(scoreString, (panelWidth - fmSmall.stringWidth(scoreString)) / 2, panelHeight / 3 + 25); g.drawString(missedAliensString, (panelWidth - fmSmall.stringWidth(missedAliensString)) / 2, panelHeight / 3 + 50); g.drawString(accuracy, (panelWidth - fmSmall.stringWidth(accuracy)) / 2, panelHeight / 3 + 75); } Toolkit.getDefaultToolkit().sync();//makes smooth controling g.dispose(); } void fire() { totalMissiles++; missiles.add(new Missile((int)(craftX + craftDimension.getWidth()), (int)(craftY + craftDimension.getHeight()/2), missileDimension)); } void gameOver(Graphics g) { Graphics g1 = g; String over = "GAME OVER"; Font fontLarge = new Font("Arial", Font.BOLD, 20); g1.setFont(fontLarge); FontMetrics fmLarge = g1.getFontMetrics(); g1.setColor(Color.WHITE); g1.drawString(over, (panelWidth - fmLarge.stringWidth(over)) / 2, panelHeight / 2); timer.stop(); alienTimer.stop(); } void setStatistic() { statistic = true; repaint(); } public void actionPerformed(ActionEvent event) { if(craftVisible) { craftX += craftDX; craftY += craftDY; if(craftX < 1) craftX = 1; if(craftX > (int)(panelWidth - craftDimension.getWidth())) craftX = (int)(panelWidth - craftDimension.getWidth()); if(craftY < 1) craftY = 1; if(craftY > (int)(panelHeight - craftDimension.getHeight())) craftY = (int)(panelHeight - craftDimension.getHeight()); } repaint(); } ////// PRIVATE INNER CLASS FOR KeyAdapter //////// private class MovementHandler extends KeyAdapter { public void keyPressed(KeyEvent event) { int keycode = event.getKeyCode(); switch(keycode) { case(KeyEvent.VK_UP): craftDY = -2; break; case(KeyEvent.VK_DOWN): craftDY = 2; break; case(KeyEvent.VK_LEFT): craftDX = -2; break; case(KeyEvent.VK_RIGHT): craftDX = 2; break; case(KeyEvent.VK_SPACE): fire(); break; } } public void keyReleased(KeyEvent event) { int keycode = event.getKeyCode(); switch(keycode) { case(KeyEvent.VK_UP): craftDY = 0; break; case(KeyEvent.VK_DOWN): craftDY = 0; break; case(KeyEvent.VK_LEFT): craftDX = 0; break; case(KeyEvent.VK_RIGHT): craftDX = 0; break; } } } ////// PRIVATE INNER CLASS FOR ActionListener(alienTimer) //////// private class AlienListener implements ActionListener { public void actionPerformed(ActionEvent event) { Random r = new Random(); alienDelay = r.nextInt(1500) + 50; alienTimer.setDelay(alienDelay); int randomLoc = r.nextInt(266); aliens.add(new Aliens(panelWidth, randomLoc, alienDimension)); } } ////// PRIVATE INNER CLASS FOR TimerTask(statisticTimer) //////// private class Statistic implements ActionListener { public void actionPerformed(ActionEvent event) { setStatistic(); } } } class Missile { int x; int y; boolean missileVisible = true; Rectangle rectangleMissile; Point pointMissile; Missile(int x, int y, Dimension d) { this.x = x; this.y = y; pointMissile = new Point(x, y); rectangleMissile = new Rectangle(pointMissile, d); } void setX(int x) { this.x += x; } int getX() { return x; } int getY() { return y; } void setRectangle() { rectangleMissile.setLocation(x, y); } Rectangle getRectangle() { return rectangleMissile; } void setVisible(boolean v) { missileVisible = v; } boolean visible() { return missileVisible; } } class Aliens { boolean alienVisible = true; int x; int y; Point pointAlien; Rectangle rectangleAlien; Aliens(int x, int y, Dimension d) { this.x = x; this.y = y; pointAlien = new Point(x, y); rectangleAlien = new Rectangle(pointAlien, d); } void setX(int d) { x -= d; } public int getX() { return x; } public int getY() { return y; } void setRectangle() { rectangleAlien.setLocation(x, y); } Rectangle getRectangle() { return rectangleAlien; } void setVisible(boolean v) { alienVisible = v; } boolean visible() { return alienVisible; } }