我正在尝试用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课程?
答案 0 :(得分:11)
您的游戏循环(模型)不应该靠近任何GUI类(视图)。它使用您的GUI类 - 但即使您可能想要通过中介(控制器)。确保你正确行事的一个好方法是检查你的模型没有一个“包括javax.swing。???”。
你能做的最好的事情就是让游戏循环保持在自己的线程中。无论何时想要在GUI中进行更改,都可以使用SwingWorker或者小孩现在使用的任何内容来强制它进入GUI线程,只进行一次操作。
这实际上很棒,因为它让您考虑GUI操作(构成您的控制器)。例如,您可能有一个名为“Move”的类,它具有移动后面的GUI逻辑。您的游戏循环可以使用正确的值(要移动的项目,最终位置)实例化“移动”并将其传递给GUI循环进行处理。
一旦达到这一点,您就会意识到只需为每个GUI操作添加一个简单的“撤消”,您就可以轻松撤消任意数量的操作。您还会发现使用Web GUI替换Swing GUI更容易......
答案 1 :(得分:5)
你需要一个游戏循环线程和一个线程来处理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
}
}
答案 2 :(得分:4)
Java非常适合event-driven programming。基本上,设置一个计时器事件并监听。在每个'tick-tock',你更新你的游戏逻辑。在每个GUI事件中,您都会更新游戏逻辑方法将读取的数据结构。