简单游戏中的 CardLayout 无法正确切换 JPanel

CardLayout in simple Game doesn't switch the JPanel properly

我正在为我的学习开发游戏的重制版本 'Breakout',但我遇到了一个奇怪的问题:

我有一个简单的开始屏幕,玩家应该可以在其中输入姓名并查看当前的最高分等。为了开始游戏,我使用了应该切换到 gamePanel 的 CardLayout。不知何故,这并没有发生,但是游戏循环开始了,当球离开 JPanel 时,我收到 game Over 消息。奇怪的是,gamePanel 与游戏 Over JOptionPane 一起出现,并且切换回开始屏幕工作正常。我也在 Whosebug 上进行了很多搜索,但是 none 我找到的解决方案对我有用。这是我的代码:

这是我的Game.java,主要方法所在的位置:

public class Game  extends JFrame {
    private static final int width = 1280;
    private static final int height = 720;
    private static final String LOBBY_PANEL = "Lobby Panel";
    private static final String GAME_PANEL = "Game Panel";
    private boolean run = false;
    private CardLayout cardLayout;
    private JPanel cardPanel = new JPanel();
    private LobbyPanel lobbyPanel;
    private GamePanel gamePanel;

    public Game(){
        super("Breakout Remastered");
        cardPanel.setLayout(new CardLayout());
        cardLayout = (CardLayout) cardPanel.getLayout();
        lobbyPanel = new LobbyPanel(this);
        gamePanel = new GamePanel(this);
        cardPanel.add(lobbyPanel, LOBBY_PANEL);
        cardPanel.add(gamePanel, GAME_PANEL);
        this.add(cardPanel);
        this.pack();
        this.setSize(width, height);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);
        cardLayout.show(cardPanel, LOBBY_PANEL);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Game gameFrame = new Game();
            gameFrame.setVisible(true);
        });

    }

    public void playGame() {
        cardLayout.show(cardPanel, GAME_PANEL);
        this.validate();
        this.repaint();
        this.run = true;

        while (run) {
            gamePanel.move();
            gamePanel.repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException iEx) {
                iEx.printStackTrace();
            }
        }
    }

    public void stopGame() {
        cardLayout.show(cardPanel, LOBBY_PANEL);
        this.run = false;
    }
}

这是我的 GamePanel.java:

public class GamePanel extends JPanel {
    private Game game;
    private Ball ball = new Ball(this);
    private Racquet racquet = new Racquet(this);

    public GamePanel(Game game) {
        this.game = game;
        KeyListener keyListener = new KeyListener() {
            @Override
            public void keyTyped(KeyEvent keyEvent) {

            }

            @Override
            public void keyPressed(KeyEvent keyEvent) {
                racquet.keyPressed(keyEvent);
            }

            @Override
            public void keyReleased(KeyEvent keyEvent) {
                racquet.keyReleased(keyEvent);
            }
        };
        addKeyListener(keyListener);
        setFocusable(true);
    }

    public void move() {
        ball.move();
        racquet.move();
    }

    public void reset() {

    }

    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        Graphics2D g2d = (Graphics2D) graphics;
        g2d.setColor(Color.BLACK);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        ball.paint(g2d);
        racquet.paint(g2d);
    }

    public void gameOver() {
        JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
        game.stopGame();
    }


    public Racquet getRacquet() {
        return racquet;
    }

    public void setRacquet(Racquet racquet) {
         this.racquet = racquet;
    }
}

这是我的 LobbyPanel.java:

public class LobbyPanel extends JPanel implements ActionListener {

    private static final JLabel labelForUserTextField = new JLabel("Username");
    private JTextField userName = new JTextField("", 20);
    private JButton startButton = new JButton("Play!");
    private JButton highScoreButton = new JButton("View Best");
    private JButton cancelButton = new JButton("Cancel");
    private Game game;

    public LobbyPanel(Game game) {

        startButton.addActionListener(this);

        this.game = game;
        this.setLayout(new GridBagLayout());
        this.setBorder(new EmptyBorder(10, 10, 10, 10));
        GridBagConstraints labelConst = new GridBagConstraints();
        labelConst.insets = new Insets(3, 3, 3, 3);

        labelConst.gridx = 0;
        labelConst.gridy = 0;
        this.add(labelForUserTextField, labelConst);
        labelConst.gridx = 1;
        this.add(userName, labelConst);
        labelConst.gridx = 0;
        labelConst.gridy = 1;
        this.add(cancelButton, labelConst);
        labelConst.gridx = 1;
        this.add(highScoreButton, labelConst);
        labelConst.gridx = 2;
        this.add(startButton, labelConst);

    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        try {
            if(actionEvent.getSource() == this.startButton) {
                this.game.playGame();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

我希望有人能弄清楚为什么这段代码不能按预期工作。 提前致谢!

发现问题如Frakcool所述:while(true){...阻塞了GUI,所以我将其替换为线程,现在可以使用了。