我将游戏写成大学项目。它使用JCanvas来显示游戏并且该部分完全正常工作,但我想添加一个菜单,您可以在其中选择" play" "高分" "出口"等。
我有一个包含JCanvas和JPanel的JFrame(后者是菜单)。但是,如果我从面板开始游戏,框架会冻结 我运行了一些测试,问题是当从JPanels actionListener调用playGame()方法时,画布无法更新,直到该方法返回。
以下是相关部分:
public class Main {
public static Game game = new Game();
private static JFrame mainFrame = new JFrame("Snake");
private static MenuPanel menuPanel = new MenuPanel();
public static void main(String[] args) {
mainFrame.setLayout(new BorderLayout());
mainFrame.add(menuPanel, BorderLayout.SOUTH);
mainFrame.pack();
mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
}
static void playGame(){
mainFrame.setVisible(false);
mainFrame.remove(menuPanel);
menuPanel.setEnabled(false);
ScoreboardPanel scoreboardPanel = new ScoreboardPanel();
mainFrame.add(scoreboardPanel, BorderLayout.NORTH);
game.addPanel(scoreboardPanel);
mainFrame.add(game, BorderLayout.CENTER);
mainFrame.pack();
mainFrame.setVisible(true);
// ANYTHING here stops the frame's rendering until playGame() returns (like game.play() or sleep(x)
}
}
public class MenuPanel extends JPanel {
private class MenuActionListener implements ActionListener {
public void actionPerformed(ActionEvent actionEvent){
switch (actionEvent.getActionCommand()){
case "play":
// TODO This somehow breaks everything. The game loop runs but the window freezes.
Main.playGame();
break;
case "highscore":
break;
case "leveleditor":
break;
case "exit":
System.exit(0);
break;
}
}
}
如果有更多帮助,可以使用完整的代码:https://github.com/nodar86/prog3-snake
答案 0 :(得分:2)
重绘和事件发送均在The Event Dispatch Thread(EDT)上执行。从事件监听器调用Game.play
方法并使用sleep
阻止EDT,因此Swing没有机会重新绘制您的帧。
解决此问题的最简单方法 - 使用javax.swing.Timer替换Game.play
中的手工制作计时器。在计时器的每个滴答声中,您应该在游戏的时间点模拟。这将允许Swing根据需要重新绘制。如果您事先准备好计时器,您的菜单听众可以启动和停止它。
附注:可能,值得您使用special menu components菜单。
答案 1 :(得分:2)
你没有使用" JCanvas"没有" JCanvas"除非你自己制作了#34; Canvas" (in here your Game class extends Canvas.)我建议您更新游戏,以便不再在同一个GUI中混合使用轻量级和重量级工具包。但看起来你几乎已经完成了,所以试试kgeorgiy的答案。