在不冻结UI线程的情况下实现游戏循环的最佳方法 [英] Best way to implement game loop without freezing UI thread

查看:82
本文介绍了在不冻结UI线程的情况下实现游戏循环的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试用Java制作一个简单的2D游戏.

I'm trying to make a simple 2D game in Java.

到目前为止,我有一个带有菜单栏的JFrame和一个扩展JPanel并覆盖它的paint方法的类.现在,我需要进行一个游戏循环,在该循环中我将更新图像的位置,依此类推.但是,我一直坚持如何最好地实现这一目标.我是否应该使用多线程,因为可以肯定的是,如果在主线程上进行无限循环,UI(以及我的菜单栏)将会冻结?

So far I have a JFrame, with a menubar, and a class which extends JPanel and overrides it's paint method. Now, I need to get a game loop going, where I will update the position of images and so on. However, I'm stuck at how best to achieve this. Should I use multi-threading, because surely, if you put an infinite loop on the main thread, the UI (and thus my menu bar) will freeze up?

到目前为止,这是我的代码:

Here's my code so far:

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班级?

Any pointers or tips? Where should I put my loop? In my main class, or my GameCanvas class?

推荐答案

您需要一个线程进行游戏循环,并需要一个线程来处理诸如鼠标单击和按键操作之类的Swing UI事件.

You need one thread for you game loop and one thread to handle Swing UI events like mouse clicks and keypresses.

使用Swing API时,您会为UI自动获得一个名为事件分发线程的附加线程.您的回调将在此线程上执行,而不是在主线程上执行.

When you use the Swing API, you automatically get an additional thread for your UI called the event dispatch thread. Your callbacks are executed on this thread, not the main thread.

如果您希望游戏在程序运行时自动启动,则您的主线程适合您的游戏循环.如果要使用Swing GUI启动和停止游戏,然后让主线程启动GUI,则当用户要启动游戏时,GUI可以为游戏循环创建新线程.

Your main thread is fine for your game loop if you want the game to start automatically when the programs runs. If you want to start and stop the game with a Swing GUI, then have then main thread start a GUI, then the GUI can create a new thread for the game loop when the user wants to start the game.

否,如果将游戏循环置于主线程中,菜单栏将不会冻结.如果您的Swing回调需要很长时间才能完成,则菜单栏将冻结.

No, your menu bar will not freeze up if you put your game loop in the main thread. Your menu bar will freeze up if your Swing callbacks take a long time to finish.

线程之间共享的数据将需要使用锁进行保护.

Data that is shared between the threads will need to be protected with locks.

我建议您将Swing代码放入其自己的类中,并且仅将游戏循环放入主类中.如果您在游戏循环中使用主线程,那么这是如何设计的粗略思路.

I suggest you factor your Swing code into its own class and only put your game loop inside your main class. If you're using the main thread for your game loop, this is a rough idea of how you could design it.

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    
    }
}

这篇关于在不冻结UI线程的情况下实现游戏循环的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆