Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to implement game loop without freezing UI thread

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

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

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

like image 320
Matthew H Avatar asked May 18 '10 23:05

Matthew H


1 Answers

Your game loop (model) should not be anywhere near any of your GUI classes (view). It uses your GUI classes--but even that you probably want to do through an intermediary (controller). A good way to ensure that you are doing it right is to check that your model doesn't have a single "include javax.swing.???".

The best thing you could do is to keep the game loop in it's own thread. Whenever you want to make a change in the GUI, use SwingWorker or whatever the young kids use now to force it onto the GUI thread for just that one operation.

This is actually awesome because it makes you think in terms of GUI Operations (which would constitute your controller). For instance, you might have a class called "Move" that would have the GUI logic behind a move. Your game loop might instantiate a "Move" with the right values (item to move, final location) and pass it to a GUI loop for processing.

Once you get to that point, you realize that simply adding a trivial "undo" for each GUI operation allows you to easily undo any number of operations. You will also find it easier to replace your Swing GUI with a web GUI...

like image 90
Bill K Avatar answered Oct 17 '22 07:10

Bill K