【问题标题】:Thread errors when running Java game运行 Java 游戏时出现线程错误
【发布时间】:2015-08-16 14:22:40
【问题描述】:

我在运行我的 Java 游戏时遇到了一些奇怪的错误。作为我的计算机科学课程的一个项目,我已经为这个游戏工作了数周,它将于 2015 年 6 月 4 日到期,所以我感谢任何帮助。最初,我在一个名为 Game 的类中编写游戏,并从一个名为 run 的静态方法运行它。后来,我决定在一个名为 Control 的类中添加一个 GUI 菜单。为了现在运行游戏,我调用了 Control 类中的 main 方法。这个菜单有一个带有动作监听器的按钮。单击按钮时,会调用 Game 类中的 run 方法。如果我单击并直接运行运行方法,则游戏可以正常运行。但是如果我点击调用 run 方法的按钮,它会绘制一个框架,而不是实际的游戏。

这是我的 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();
    }
}

这是我的游戏类中的运行方法:

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

如果我直接调用 run 方法,它会起作用,但如果我单击 GUI 中的按钮,则不会。我感觉这是一个线程问题,因为一旦调用 run,主线程就会结束。不过,我不是 100% 确定原因。如果您有任何回复,我将不胜感激,作为我的计算机科学课程的项目,我已经为这款游戏工作了数周,它将于 2015 年 6 月 4 日到期。

【问题讨论】:

    标签: java multithreading swing awt event-dispatch-thread


    【解决方案1】:

    Swing 是单线程的——所有的绘画、事件等...都发生在这个线程上(命名为EDT)。在 EDT 上调用 Game.run 方法,该方法又执行一个长时间运行的任务(例如 while (true)Thread.sleep)——这会阻止 EDT 执行任何其他操作。要执行动画,请考虑使用 Thread,或者更好的是 Swing Timer

    【讨论】:

    • Swing Timer 很简单,但是如果你要告诉他们创建一个线程,那么你也应该说线程不能调用除SwingUtilities.invokeLater() 之外的任何 Swing 方法。跨度>
    • @copeg 非常感谢。我创建了一个新线程并从那里调用了我的 run 方法,现在一切正常。
    • @user1615326,如果使用线程,请注意上面的@james 大注释 RE:对 Swing 的调用(例如 repaintrequestFocusInWindow)应使用 SwingUtilities.invokeLater 发送到 EDT。
    • 谢谢,我会改变我的代码来做到这一点。一个简单的问题,即使我在不​​使用SwingUtilities.invokeLater 的情况下调用repaint,我的代码也能正常工作。为什么我必须使用SwingUtilities.invokeLater?有什么好处吗?
    猜你喜欢
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    • 2020-05-11
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多