簡體   English   中英

實現游戲循環而不凍結UI線程的最佳方法

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM