どちらも再描画とイベントディスパッチは(The Event Dispatch Thread上で実行されます。それはより多くの場合に役立ちます
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;
}
}
}
そして、ここでは完全なコードです:ここで
は、関連する部分ですEDT)。
Game.play
メソッドがイベントリスナーから呼び出され、
sleep
を使用してEDTをブロックするため、Swingはフレームを再描画する機会がありません。
これを直す最も簡単な方法は、Game.play
のハンドメイドタイマーをjavax.swing.Timerに置き換えます。タイマーの各ティックでは、ゲームのチックでエミュレートする必要があります。これにより、必要に応じてSwingを再描画することができます。あらかじめタイマーを準備しておけば、メニューリスナーはそれを開始して止めることができます。
サイドノート:おそらく、あなたのメニューにはspecial menu componentsを使用する価値があります。
ありがとうございました。また、EDTに関する情報をリンクして説明してくれてありがとう。これはすべてのものがスイングするのに役立ちます! –