[英]Best way to implement game loop without freezing UI thread
我正在嘗試用Java制作一個簡單的2D游戲。
到目前為止,我有一個帶有菜單欄的JFrame
,以及一個擴展JPanel
並覆蓋它的paint
方法的類。 現在,我需要進行游戲循環,在那里我將更新圖像的位置等等。 但是,我堅持如何最好地實現這一目標。 我應該使用多線程,因為當然,如果你在主線程上放置一個無限循環,UI(以及我的菜單欄)會凍結嗎?
到目前為止,這是我的代碼:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class GameCanvas extends JPanel {
public void paint(Graphics g) {
while (true) {
g.setColor(Color.DARK_GRAY);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
@SuppressWarnings("serial")
public class Main extends JFrame {
GameCanvas canvas = new GameCanvas();
final int FRAME_HEIGHT = 400;
final int FRAME_WIDTH = 400;
public static void main(String args[]) {
new Main();
}
public Main() {
super("Game");
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem startMenuItem = new JMenuItem("Pause");
menuBar.add(fileMenu);
fileMenu.add(startMenuItem);
super.add(canvas);
super.setVisible(true);
super.setSize(FRAME_WIDTH, FRAME_WIDTH);
super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
super.setJMenuBar(menuBar);
}
}
任何指針或提示? 我應該把我的循環放在哪里? 在我的主要課程中,還是我的GameCanvas課程?
您的游戲循環(模型)不應該在任何GUI類(視圖)附近。 它使用您的GUI類 - 但即使您可能想要通過中介(控制器)。 確保您正確執行的一個好方法是檢查您的模型沒有單個“include javax.swing。???”。
你可以做的最好的事情是讓游戲循環保持在自己的線程中。 無論何時想要在GUI中進行更改,都可以使用SwingWorker或者小孩現在使用的任何內容來強制它進入GUI線程以進行一次操作。
這實際上很棒,因為它讓你考慮GUI操作(構成你的控制器)。 例如,您可能有一個名為“Move”的類,它具有移動后面的GUI邏輯。 您的游戲循環可能會使用正確的值(要移動的項目,最終位置)實例化“移動”並將其傳遞給GUI循環進行處理。
一旦達到這一點,您就會意識到只需為每個GUI操作添加一個簡單的“撤消”,就可以輕松撤消任意數量的操作。 您還會發現使用Web GUI替換Swing GUI更容易......
你需要一個線程為你的游戲循環和一個線程來處理Swing UI事件,如鼠標點擊和按鍵。
使用Swing API時,會自動為UI獲取一個名為事件派發線程的附加線程。 你的回調是在這個線程上執行的,而不是主線程。
如果您希望游戲在程序運行時自動啟動,那么您的主線程適合您的游戲循環。 如果你想用Swing GUI開始和停止游戲,然后主線程啟動一個GUI,那么當用戶想要開始游戲時,GUI可以為游戲循環創建一個新線程。
不,如果您將游戲循環放在主線程中,您的菜單欄將不會凍結。 如果你的Swing回調需要很長時間才能結束,你的菜單欄會凍結。
線程之間共享的數據需要使用鎖保護。
我建議你將你的Swing代碼考慮到它自己的類中,並且只將你的游戲循環放在你的主類中。 如果你在游戲循環中使用主線程,那么你就可以大致了解如何設計它。
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
class GUI extends JFrame {
GameCanvas canvas = new GameCanvas();
final int FRAME_HEIGHT = 400;
final int FRAME_WIDTH = 400;
public GUI() {
// build and display your GUI
super("Game");
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem startMenuItem = new JMenuItem("Pause");
menuBar.add(fileMenu);
fileMenu.add(startMenuItem);
super.add(canvas);
super.setVisible(true);
super.setSize(FRAME_WIDTH, FRAME_WIDTH);
super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
super.setJMenuBar(menuBar);
}
}
public class Main {
public static void main(String args[]) {
GUI ui = new GUI(); // create and display GUI
gameLoop(); // start the game loop
}
static void gameLoop() {
// game loop
}
}
Java非常適合事件驅動編程 。 基本上,設置一個計時器事件並監聽。 在每個'tick-tock',你更新你的游戲邏輯。 在每個GUI事件中,您都會更新游戲邏輯方法將讀取的數據結構。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.