如何在 Swing 中获得最接近“暂停”的效果?

问题描述 投票:0回答:1

我必须使用 Swing 在 Java 中编写一个小游戏,并且我需要做一件非常具体的事情,但我一生都无法弄清楚。

问题方法如下:

static void aiTurn() {

        boolean attackableNeighbour = true;

        while (attackableNeighbour) {
            attackableNeighbour = false;
            for (int i = 0; i < DicePanel.ROWS; i++) {
                for (int j = 0; j < DicePanel.COLUMNS; j++) {
                    if (!cells[i][j].getIsPlayer()) {
                        int min = 9;
                        int minI = 0;
                        int minJ = 0;

                        for (int neighbourI = Math.max(0, i - 1); 
                            neighbourI <= Math.min(i + 1, cells.length - 1); neighbourI++) {
                            for (int neighbourJ = Math.max(0, j - 1); 
                                neighbourJ <= Math.min(j + 1, cells[0].length - 1); neighbourJ++) {
                                if (neighbourI != i && neighbourJ != j
                                    && cells[neighbourI][neighbourJ].getIsPlayer() 
                                    && cells[neighbourI][neighbourJ].getDiceNumber() < min) {
                                    min = cells[neighbourI][neighbourJ].getDiceNumber();
                                    minI = neighbourI;
                                    minJ = neighbourJ;
                                }
                            }
                        }

                        if (cells[i][j].getDiceNumber() >= min) {
                            attackableNeighbour = true;

                            cells[minI][minJ].setBackground(new Color(119, 82, 168));
                            cells[i][j].setBackground(new Color(121, 204, 88));

                            //pause here for a second (background needs to change)

                            attackAI(i, j, minI, minJ);

                            cells[i][j].setBackground(new Color(61, 153, 49));
                            if (cells[minI][minJ].getIsPlayer()) {
                                cells[minI][minJ].setBackground(new Color(100, 50, 168));
                            }

                            //pause here as well
                        }
                    }
                }
            }
        }
}

我需要做的是能够在那里暂停。问题是,由于所有这些都在 EDT 中,我不能只使用计时器或使用

Thread.sleep()
- GUI 不会更新。我想要的效果是 GUI 根据我的代码进行更新,而不进行下一个更改。

我尝试过使用不同的线程来执行逻辑,但无论我尝试什么,它要么不起作用,要么 EDT(for 循环)上的代码继续运行,并且新线程延迟严重,以至于破坏了整个系统。

这是我尝试过的:

 if (cells[i][j].getDiceNumber() >= min) {
     attackableNeighbour = true;

     final int altMinI = minI;
     final int altMinJ = minJ;
     final int altI = i;
     final int altJ = j;

     cells[minI][minJ].setBackground(new Color(119, 82, 168));
     cells[i][j].setBackground(new Color(121, 204, 88));

     SwingWorker worker = new SwingWorker<Object, String>() {
         @Override
         protected Object doInBackground() throws Exception {
             attackAI(altI, altJ, altMinI, altMinJ);
             Thread.sleep(1000);
             cells[i][j].setBackground(new Color(61, 153, 49));
             if (cells[minI][minJ].getIsPlayer()) {
                 cells[minI][minJ].setBackground(new Color(100, 50, 168));
             }
             return null;
         }
     };
     worker.execute();
}

这会破坏游戏,因为方法

attackAI()
在初始 for 循环结束后很长时间才会被调用。我尝试阅读很多有关多线程的帖子,但我不知所措。非常感谢您的帮助!

java swing
1个回答
0
投票

我将为所有像我一样陷入困境的人发布我自己问题的答案。谢谢camickr;他的评论帮助我实现了我想做的事。

这是更新后的代码,可以按照我的意愿工作:

static void aiTurn() {

SwingWorker<Object, String> worker = new SwingWorker<Object, String>() {

    @Override
    protected Object doInBackground() throws Exception {
        boolean attackableNeighbour = true;

        while (attackableNeighbour) {
            attackableNeighbour = false;
            for (int i = 0; i < DicePanel.ROWS; i++) {
                for (int j = 0; j < DicePanel.COLUMNS; j++) {
                    if (!cells[i][j].getIsPlayer() && cells[i][j].getDiceNumber() > 1) {
                        int min = 9;
                        int minI = 0;
                        int minJ = 0;

                        for (int neighbourI = Math.max(0, i - 1); 
                            neighbourI <= Math.min(i + 1, cells.length - 1); neighbourI++) {
                            for (int neighbourJ = Math.max(0, j - 1); 
                                neighbourJ <= Math.min(j + 1, cells[0].length - 1); neighbourJ++) {
                                if (neighbourI != i && neighbourJ != j
                                    && cells[neighbourI][neighbourJ].getIsPlayer() 
                                    && cells[neighbourI][neighbourJ].getDiceNumber() < min) {
                                    min = cells[neighbourI][neighbourJ].getDiceNumber();
                                    minI = neighbourI;
                                    minJ = neighbourJ;
                                }
                            }
                        }

                        if (cells[i][j].getDiceNumber() >= min) {
                            attackableNeighbour = true;

                            Thread.sleep(700);

                            cells[minI][minJ].setBackground(new Color(119, 82, 168));
                            cells[i][j].setBackground(new Color(121, 204, 88));

                            Thread.sleep(1000);

                            attackAI(i, j, minI, minJ);

                            cells[i][j].setBackground(new Color(61, 153, 49));
                            if (cells[minI][minJ].getIsPlayer()) {
                                cells[minI][minJ].setBackground(new Color(100, 50, 168));
                            }

                            Thread.sleep(300);
                        }
                    }
                }
            }
        }

        endTurnAI();
        return null;
    }
};

worker.execute(); }

我的疏忽是,当我只将 for 循环内的内容放入不同的线程中时,循环会在线程休眠时继续,因此会完全延迟。

但是由于每个 GUI 更改都发生在事件线程中,我可以将整个 for 循环放在不同的线程中,然后在我希望它暂停时休眠它 - GUI 仍然会更改(因为 EDT 当时为空) )并且不会有任何延迟,因为一切本质上仍然在单个线程中工作。

© www.soinside.com 2019 - 2024. All rights reserved.