Search code examples
javamultithreadingswingawtevent-dispatch-thread

Thread errors when running Java game


I am getting some strange errors when running my Java game. I've been working on this game for weeks as a project for my computer science class and it is due on 6/4/2015, so I appreciate any help. Initially I wrote the game in a class called Game and ran it from a static method called run. Later, I decided to add a GUI menu in a class called Control. To run the game now, I call the main method in the Control class. This menu has a button with an action listener. When the button is clicked, the run method in the Game class is called. If I click and run the run method directly the game works fine. But if I click the button which calls the run method it draws a frame, but not the actual game.

Here is my code for the GUI:

    public class Control extends JFrame implements ActionListener {

    // JPanel
    public JPanel pnlButton = new JPanel();

    // Buttons
    public JButton btnAddFlight = new JButton("Multiplayer");
    public JButton single = new JButton("Singleplayer");

    public Control() throws IOException,InterruptedException {
        super("Bouncy Ball");
        //Set button size
        btnAddFlight.setBounds(150, 400, 220, 30);
        single.setBounds(150,350,220,30);

        // JPanel bounds
        pnlButton.setBounds(0, 0, 500, 500);
        pnlButton.setBackground(Color.WHITE);

        // Adding the Bouncy Ball logo to JPanel
        String path = "gg.jpg";
        File file = new File(path);
        BufferedImage image = ImageIO.read(file);
        JLabel label = new JLabel(new ImageIcon(image));
        label.setBounds(179,50,150,150);

        //Action Listener setup
        single.addActionListener(this);

        //add buttons and title logo to JPanel
        pnlButton.add(btnAddFlight);
        pnlButton.add(label);
        pnlButton.add(single);

        //Set up and add the instructions to the JPanel
        JLabel gg = new JLabel("Welcome to Bouncy Ball, a game where you have to manipulate");
        gg.setFont(new Font("Serif", Font.PLAIN, 18));
        gg.setBounds(0,10,500,500);
        pnlButton.add(gg);
        JLabel f = new JLabel("the window size with WASD to win! Click the buttons to start.");
        f.setFont(new Font("Serif", Font.PLAIN, 18));
        f.setBounds(0,28,500,500);
        pnlButton.add(f);
        pnlButton.setLayout(null);

        //Add JPanel to JFrame
        this.add(pnlButton);

        // JFrame properties
        setSize(500, 500);       
        setTitle("Bouncy Ball");
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);;
    }

    @Override
    public void actionPerformed(ActionEvent submitClicked) {
        try{
            isClicked = true;

            Game.run();
        }
        catch(InterruptedException a){}
    }

    public static void main(String[] args) throws IOException,InterruptedException{
        new Control();
    }
}

and here is the run method in my game class:

public static void run() throws InterruptedException {
    //Setting up JFrame
    frame = new KeyFrame("Bouncy Ball");
    frame.setSize(1000, 1000);

    //Setting up Scanner and get user level input
    Scanner scan = new Scanner (System.in);
    System.out.println("Level one, two, three, or four?(must be an int, four is multiplayer)");
    f = scan.nextInt();

    //Display JFrame
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.toFront();

    //Add Game JPanel
    game = new Game();
    frame.add(game);

    //Setting up game basics
    b = new Ball(game,0,0,30,30);
    setUpLevel();
    objList.add(0,b);

    //Main Game Loop
    while (true) {
        //Request Focus
        game.requestFocusInWindow();

        //Update current Time
        lastStartTime = System.currentTimeMillis();

        //Move the ball and the player
        p.move();
        b.move();

        //Refresh JPanel
        game.repaint();
        Thread.sleep(10);

        //Check if the player wins or loses
        checkWin();
        checkLoss();
    }
}

If I call the run method directly it works, but not if I click the button in the GUI. I have a feeling that it is a thread issue, because the main thread ends once run is called. I'm not a 100% percent sure as to the cause though. I'd appreciate any responses, I've been working on this game for weeks as a project for my computer science class and it is due on 6/4/2015.


Solution

  • Swing is single threaded - all painting, events, etc...occur on this thread (named the EDT). The Game.run method is called on the EDT, which in turn executing a long running task (eg while (true), Thread.sleep) - this prevents the EDT from doing anything else. To perform animation, consider using a Thread, or better yet a Swing Timer.