6

我正在用 java 制作井字游戏程序,因为我正在学习 java,我认为一个简单的项目将是一个很好的起点。到目前为止,这是我的代码:

public class Start {
    public static void main(String[] args) {
    GameTicTacToe gameTicTacToe = new GameTicTacToe();
    gameTicTacToe.windowBirth();

    }
}

和,

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GameTicTacToe implements ActionListener {
    private int gridSize = 3;
    private JButton[] gridButton = new JButton[(gridSize * gridSize)];
    private JPanel grid = new JPanel(new GridLayout(gridSize, gridSize, 0, 0));
    private JFrame windowTicTacToe = new JFrame("Tisk, Task, Toes");
    private int[] gridButtonOwner = new int[(gridSize * gridSize)];
    private int turn = 1;
    private int HolerHor, HolerVer, HolerDia1, HolerDia2;

    Thread winnerBlue = new Thread() {
        public void run() {
            for (int a = 0; a < 4; a++) {
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.BLUE);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.WHITE);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
            }
            for (int i = 0; i < gridButton.length; i++) {
                gridButton[i].setEnabled(true);
                gridButtonOwner[i] = 0;
            }
        }
    };
    Thread winnerRed = new Thread() {
        public void run() {
            for (int a = 0; a < 4; a++) {
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.RED);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.WHITE);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
            }
            for (int i = 0; i < gridButton.length; i++) {
                gridButton[i].setEnabled(true);
                gridButtonOwner[i] = 0;
            }
        }
    };
    public void windowBirth() {
        for (int i = 0; i < gridButton.length; i++) {
            gridButtonOwner[i] = 0;
            gridButton[i] = new JButton("");
            gridButton[i].addActionListener(this);
            gridButton[i].setBackground(Color.WHITE);
            grid.add(gridButton[i]);
        }
        windowTicTacToe.setDefaultCloseOperation(3);
        windowTicTacToe.setLocation(400, 200);
        windowTicTacToe.setPreferredSize(new Dimension(400, 400));
        windowTicTacToe.add(grid);
        windowTicTacToe.pack();
        windowTicTacToe.setVisible(true);
    }
    public void actionPerformed(ActionEvent gridButtonClicked) {
        for (int i = 0; i < gridButton.length; i++) {
            if (gridButtonClicked.getSource() == gridButton[i]) {
                if (turn == 1) {
                    turn = 2;
                    gridButtonOwner[i] = 1;
                    gridButton[i].setBackground(Color.blue);
                    gridButton[i].setEnabled(false);
                } else {
                    turn = 1;
                    gridButtonOwner[i] = 2;
                    gridButton[i].setBackground(Color.red);
                    gridButton[i].setEnabled(false);
                }
            }
        }
        checkWinner();
    }
    public void checkWinner() {
        for (int a = 1; a < 3; a++) {
            HolerDia1 = a;
            HolerDia2 = a;
            for (int b = 0; b < gridSize; b++) {
                HolerHor = a;
                HolerVer = a;
                for (int c2 = 0; c2 < gridSize; c2++) {
                    HolerHor = (HolerHor * gridButtonOwner[((b * gridSize) + c2)])/ a;
                    HolerVer = (HolerVer * gridButtonOwner[((c2 * gridSize) + b)])/ a;
                }
                if (HolerHor == a || HolerVer == a) {
                    winnerAnimation(a);
                }
            }
            for(int h = 0;h < gridSize; h++){
                HolerDia1 = (HolerDia1 * gridButtonOwner[h * (gridSize + 1)]) / a;
                HolerDia2 = (HolerDia2 * gridButtonOwner[(h * (gridSize - 1)) + (gridSize - 1)]) / a;
            }
            if (HolerDia1 == a || HolerDia2 == a) {
                winnerAnimation(a);
            }
        }
    }
    public void winnerAnimation(int b) {
        for (int i = 0; i < gridButton.length; i++) {
            gridButton[i].setEnabled(false);
        }
        if (b == 1){
            winnerBlue.start();
        }else{
            winnerRed.start();
        }
    }
}

这是我的问题,当玩家获胜时,例如玩家 1(蓝色),它会播放动画(闪烁蓝板)。但是当玩家 1 再次获胜时,程序崩溃了。

我调查了一下,发现你不能启动一个线程两次,因为你不能。

我将如何暂停线程,然后在需要时重新启动它?

4

6 回答 6

6

您可以简单地创建一个新线程并在需要时运行它。但无论如何,我会使用 Swing Timer 来制作动画,因为它更简单、更安全,因为您不必担心意外踩到 Swing 线程(EDT)而导致的有害间歇性崩溃。

例如,

   public void myWinner(final Color flashColor) {
      int timerDelay = 300;
      new javax.swing.Timer(timerDelay , new ActionListener() {
         private static final int COUNTER_MAX = 5;
         int counter = 0;

         public void actionPerformed(ActionEvent e) {
            if (counter >= COUNTER_MAX) { // time to stop
               ((Timer)e.getSource()).stop();
               for (int i = 0; i < gridButton.length; i++) {
                  gridButton[i].setBackground(Color.white); // just to be sure
                  gridButton[i].setEnabled(true);
                  gridButtonOwner[i] = 0;
               }
            }
            Color bckgrndColor = (counter % 2 == 0) ? flashColor : Color.white;
            for (JButton button : gridButton) {
               button.setBackground(bckgrndColor);
            }
            counter++;
         }
      }).start();
   }
于 2011-04-09T22:34:48.070 回答
3

在您的情况下,在重播动画线程的情况下,您可能希望:

  • 将线程封装为它自己的对象,例如,与其创建匿名对象,Runnable不如创建一个匿名对象。ThreadRunnable
  • 然后只需重新创建线程并启动它:

    public void winnerAnimation(int b)
    {
        ...
        if (b == 1)
        {
            animationThread = new Thread(winnerBlue);
            animationThread.start();
        }
        else
        {
            animationThread = new Thread(winnerRed);
            animationThread.start();
        }
    }
    

    Thread顺便说一句,您可能需要考虑在编写您的 s 或s时 Swing 不是线程安全的事实Runnable

于 2011-04-09T22:30:38.287 回答
3

使用信号量

  1. 在程序开始时启动线程。
  2. 每个 run() 方法都应该连续循环。
  3. 在循环的顶部,acquire() 适当的信号量(红色/蓝色)。
  4. 当检测到获胜者时,释放()适当的信号量。
于 2011-04-09T22:31:27.550 回答
2

创建另一个线程实例有什么问题?重用线程很讨厌,会导致非常奇怪的行为,通常不应该这样做。

除了代码的重复(线程中只有 1 行差异,对吗?),您可以简单地将线程实现为内部类。这样您就不必使用匿名实例,您可以根据需要重新创建和启动多次。
您应该明确考虑将颜色作为参数添加到此线程!

(我很确定这里有编译器错误,但你应该明白我的意思。)

// other stuff here...

public void winnerAnimation(int b) {
    for (int i = 0; i < gridButton.length; i++) {
        gridButton[i].setEnabled(false);
    }
    if (b == 1){
        new WinnerThread(Color.BLUE).start();
    }else{
        new WinnerThread(Color.RED).start();
    }
}

class WinnerThread extends Thread {
   private Color color;
   public WinnerThread(Color c)
   {
       color = c;
   }

   public void run() {
            for (int a = 0; a < 4; a++) {
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(color);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
                for (int i = 0; i < gridButton.length; i++) {
                    gridButton[i].setBackground(Color.WHITE);
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                }
            }
            for (int i = 0; i < gridButton.length; i++) {
                gridButton[i].setEnabled(true);
                gridButtonOwner[i] = 0;
            }
        }
    }
}
于 2011-04-09T22:47:21.607 回答
1

看看java的wait()notify()方法。是关于它们的教程。

于 2011-04-09T22:32:00.123 回答
0

可以使用以下函数暂停和恢复线程:

  • suspend() = 暂停
  • resume() = 用于恢复

执行:

线程对象暂停();

线程对象简历();

但我认为这些功能已被弃用。不过不确定。

于 2013-06-13T07:51:30.590 回答