如何让程序正常重启? (砖破碎机)

时间:2016-02-23 02:45:11

标签: java swing keylistener java-2d thread-sleep

当gameover为true并且我从DOWN按钮KeyListener调用startGame方法时,它会破坏我的游戏,并且不允许我单击JFrame上的退出按钮并且paddle不再起作用。请帮忙。

import javax.swing.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Image;
public class AustinsBrickBreaker {
    JFrame window;
    DrawPanel panel;
    public AustinsBrickBreaker() {
        window = new JFrame("Brick Breaker");
        panel = new DrawPanel();
        window.setSize(800, 592);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.getContentPane().add(panel);
        window.setLocationRelativeTo(null);
        window.setVisible(true);
        window.setResizable(false);
    }
    public void go() {
        panel.startGame();
    }
    public static void main(String[] args) {
        AustinsBrickBreaker game = new AustinsBrickBreaker();
        game.go();
    }
}
@SuppressWarnings("serial")
class DrawPanel extends JPanel implements KeyListener {
    final int WIDTH = 800, HEIGHT = 592;
    BufferedImage buffer;
    public static Brick[][] bricks = new Brick[3][5];
    Paddle paddle;
    Ball ball;
    int score = 0;
    int lives = 3;
    boolean gameover = false;
    Image brickImage = Toolkit.getDefaultToolkit().getImage("brick.png");
    Image brickImage2 = Toolkit.getDefaultToolkit().getImage("brick2.png");
    Image brickImage3 = Toolkit.getDefaultToolkit().getImage("brick3.png");
    Image brickImage4 = Toolkit.getDefaultToolkit().getImage("brick4.png");
    Image brickImage5 = Toolkit.getDefaultToolkit().getImage("brick5.png");
    Image paddleImage = Toolkit.getDefaultToolkit().getImage("paddle.png");
    Image background = Toolkit.getDefaultToolkit().getImage("background.jpg");
    Image ballImage = Toolkit.getDefaultToolkit().getImage("ball.png");
    Image heartImage = Toolkit.getDefaultToolkit().getImage("heart.png");
    public DrawPanel() {
        setIgnoreRepaint(true);
        addKeyListener(this);
        setFocusable(true);
    }
    public void keyTyped(KeyEvent e) {}
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) paddle.left = true;
        if (key == KeyEvent.VK_RIGHT) paddle.right = true;
        if (key == KeyEvent.VK_UP && gameover) {
            gameover = false;
            score = 0;
            lives = 3;
            startGame();
        }
        if (key == KeyEvent.VK_DOWN && gameover) System.exit(0);
    }
    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();
        if (key == KeyEvent.VK_LEFT) paddle.left = false;
        if (key == KeyEvent.VK_RIGHT) paddle.right = false;
    }
    public int count() {
        int count = 0;
        for (int r = 0; r < DrawPanel.bricks.length; r++)
        for (int c = 0; c < DrawPanel.bricks[r].length; c++)
        if (!bricks[r][c].visible) count++;
        else
        break;
        int returner = 0;
        if (count == 15) returner = 1;
        return returner;
    }
    public void initialize() {
        buffer = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        for (int r = 0; r < DrawPanel.bricks.length; r++)
        for (int c = 0; c < DrawPanel.bricks[r].length; c++)
        DrawPanel.bricks[r][c] = new Brick(c * 150 + 50, r * 60 + 30, 100, 50);
        ball = new Ball(390, 200, 20, 20, 10);
        paddle = new Paddle(350, 510, 100, 20, 8);
    }
    public void updateMovement() {
        paddle.move();
        ball.move();
    }
    public void checkCollisions() {
        if (paddle.x <= 20) paddle.x = 20;
        if (paddle.x >= 679) paddle.x = 679;
        if (ball.x < 21) {
            ball.left = false;
            ball.right = true;
        }
        if (ball.x > 761) {
            ball.left = true;
            ball.right = false;
        }
        if (ball.y < 21) {
            ball.up = false;
            ball.down = true;
        }
        if (paddle.getBounds().intersects(ball.getBounds())) ball.swap();
        for (int r = 0; r < DrawPanel.bricks.length; r++)
        for (int c = 0; c < DrawPanel.bricks[r].length; c++) {
            if (ball.getBounds().intersects(DrawPanel.bricks[r][c].getBounds()) && !DrawPanel.bricks[r][c].collision) {
                ball.swap();
                bricks[r][c].collide();
                score += 10;
            }
        }
    }
    public void drawBuffer() {
        Graphics2D b = buffer.createGraphics();
        b.drawImage(background, 0, 0, null);
        if (!gameover) {
            for (int l = 0; l < lives; l++)
            b.drawImage(heartImage, 20 * l + 620, 535, null);
            b.drawString("Score: " + score, 700, 550);
            b.drawImage(paddleImage, paddle.getX(), paddle.getY(), null);
            b.drawImage(ballImage, ball.getX(), ball.getY(), null);
            for (int r = 0; r < DrawPanel.bricks.length; r++)
            for (int c = 0; c < DrawPanel.bricks[r].length; c++) {
                if (bricks[r][c].visible == true)
                if (bricks[r][c].colour == 1)
                b.drawImage(brickImage, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
                else if (bricks[r][c].colour == 2)
                b.drawImage(brickImage2, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
                else if (bricks[r][c].colour == 3)
                b.drawImage(brickImage3, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
                else if (bricks[r][c].colour == 4)
                b.drawImage(brickImage4, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
                else if (bricks[r][c].colour == 5)
                b.drawImage(brickImage5, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
            }
            b.dispose();
            } else {
            b.drawString("G A M E O V E R !", 340, 300);
            b.drawString("G A M E O V E R !", 341, 300);
            b.drawString("G A M E O V E R !", 342, 300);
            b.drawString("Press ↑ To Play Again!", 332, 320);
            b.drawString("Press ↓ To Exit :(", 342, 340);
        }
    }
    public void drawScreen() {
        Graphics2D g = (Graphics2D) this.getGraphics();
        g.drawImage(buffer, 0, 0, this);
        Toolkit.getDefaultToolkit().sync();
        g.dispose();
    }
    public void startGame() {
        initialize();
        while (!gameover) {
            try {
                updateMovement();
                checkCollisions();
                drawBuffer();
                drawScreen();
                Thread.sleep(15);
                if (ball.y > 562 && lives != -1) {
                    Thread.sleep(500);
                    lives -= 1;
                    ball.x = 390;
                    ball.y = 200;
                    ball.left = false;
                    ball.right = false;
                    paddle.x = 350;
                }
                if (lives == -1) {
                    Thread.sleep(500);
                    gameover = true;
                    drawBuffer();
                    drawScreen();
                }
                //Replace Bricks
                if (count() == 1) {
                    Thread.sleep(500);
                    startGame();
                }
                } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
/*--|--|--|--| GAME CLASSES |--|--|--|--*/
class Brick {
    int x, y, width, height, colour;
    boolean collision, visible;
    public Brick(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.width = w;
        this.height = h;
        this.collision = false;
        this.visible = true;
        this.colour = (int) Math.ceil(Math.random() * 5);
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    public int getWidth() {
        return width;
    }
    public int getHeight() {
        return height;
    }
    public Rectangle getBounds() {
        return new Rectangle(getX(), getY(), getWidth(), getHeight());
    }
    public void collide() {
        if (collision == false) {
            visible = false;
            collision = true;
        }
    }
}
class Paddle {
    int x, y, width, height, speed;
    boolean left, right;
    public Paddle(int x, int y, int w, int h, int s) {
        this.x = x;
        this.y = y;
        this.width = w;
        this.height = h;
        this.speed = s;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    public int getWidth() {
        return width;
    }
    public int getHeight() {
        return height;
    }
    public Rectangle getBounds() {
        return new Rectangle(getX(), getY(), getWidth(), getHeight());
    }
    public void move() {
        if (left) x -= speed;
        if (right) x += speed;
    }
}
class Ball {
    int x, y, width, height, speed;
    boolean up, down, left, right;
    public Ball(int x, int y, int w, int h, int s) {
        this.x = x;
        this.y = y;
        this.width = w;
        this.height = h;
        this.speed = s;
        this.up = false;
        this.down = true;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
    public int getWidth() {
        return width;
    }
    public int getHeight() {
        return height;
    }
    public Rectangle getBounds() {
        return new Rectangle(getX(), getY(), getWidth(), getHeight());
    }
    public void move() {
        if (up) y -= speed;
        if (down) y += speed;
        if (left) x -= (float) Math.ceil(Math.random() * 5);
        if (right) x += (float) Math.ceil(Math.random() * 5);
    }
    public void swap() {
        if (up) {
            down = true;
            up = false;
            } else if (down) {
            up = true;
            down = false;
        }
        double r = Math.random();
        if (r <= 0.5) {
            left = false;
            right = true;
            } else if (r > 0.5) {
            left = true;
            right = false;
        } else left = true;
    }
}

2 个答案:

答案 0 :(得分:2)

您的代码完全忽略了Swing线程规则,并且在首次运行时以某种方式允许这种情况,因为首次运行时,在Swing事件线程的主线程中调用startGame()方法。但是当第二次调用它时,它会在事件线程上调用,而这次,所有这些睡眠调用都会使Swing事件线程和您的应用程序进入休眠状态。解决方案:了解Swing线程规则,让应用程序遵守这些规则,包括不调用Thread.sleep,或者在事件线程上调用永久循环。

请参阅:Lesson: Concurrency in Swing

答案 1 :(得分:2)

这不是一个答案,而是一个很长的评论

首先,getGraphics不是自定义绘画在Swing中的工作原理,你永远不应该使用它。

首先查看Painting in AWT and SwingPerforming Custom Painting,了解有关绘画在Swing中如何运作的详细信息。

Swing使用被动渲染逼近,这意味着它的绘画过程可以在任何时间发生,出于任何原因,在没有您的交互或知识的情况下,在您当前的方法下,您最终可能会遇到中间闪烁几乎不可能诊断或重复。

如果您想控制绘画(主动绘画),请查看BufferStrategyBufferStrategy and BufferCapabilities

其次,不要使用KeyListener,我可能会考虑使用KeyListener的情况非常有限,但这不是其中之一,当您发现自己想要回复时对于关键事件,您应该从the key bindings API

开始

第三,不要使用Toolkit.getDefaultToolkit().getImage,而是使用ImageIO,它支持更多图像,它会在返回之前加载图像(而不是使用后台线程)并抛出{ {1}}无法加载图片时有关详细信息,请参阅Reading/Loading an Image

第四,你违反了Swing的单线程规则。基本上,因为系统的工作方式,IOException在所谓的&#34; main&#34;线程,但Swing在它自己的线程中运行(AKA The Event Dispatching Thread)。

所以当你第一次开始时,main正在&#34; main&#34;线程,但是当你从go拨打start时,你就在EDT中运行了,这意味着你在游戏循环中#34;将阻止EDT并且没有任何东西会再次绘制,并且用户无法与您的程序进行交互。

有关详细信息,请参阅Concurrency in Swing;有关可能的解决方案,请参阅How to Use Swing Timers