10

我做了一个二十一点游戏,我想让 AI 玩家在拿牌之间停下来。我尝试简单地使用 Thread.sleep(x),但这会使其冻结,直到 AI 玩家拿完所有的牌。我知道 Swing 不是线程安全的,所以我查看了 Timers,但我不明白如何使用它。这是我当前的代码:

while (JB.total < 21) {

          try {
            Thread.sleep(1000);
          } catch (InterruptedException ex) {
            System.out.println("Oh noes!");
          }

          switch (getJBTable(JB.total, JB.aces > 0)) {
            case 0:
              JB.hit();
              break;
            case 1:
              break done;
            case 2:
              JB.hit();
              JB.bet *= 2;
              break done;
          }
        }

顺便说一句,hit(); 方法更新 GUI。

4

4 回答 4

7

所以我看了看定时器,但我不明白我怎么能用它来做这个

计时器是解决方案,因为正如您所说,您正在更新应该在 EDT 上完成的 GUI。

我不确定你关心的是什么。你发一张牌并启动计时器。当计时器触发时,您决定拿另一张牌或持有。当你按住你的停止计时器。

于 2011-08-31T03:19:57.573 回答
4

好吧,关于定时器的快速解释。

首先,您的类中需要一个 java.util.Timer 变量,项目中需要另一个从 java.util.TimerTask 扩展的类(我们称之为 Tasker)。

Timer 变量的初始化非常简单:

Timer timer = new Timer();

现在Tasker类:

public class Tasker extends TimerTask {
    @Override
    public void run() {
        actionToDo(); // For example take cards 
    }

    // More functions if they are needed
}

最后,安装定时器及其相关的Tasker:

long delay = 0L;
long period = pauseTime;
timer.schedule(new Tasker(),delay,period);

schedule 函数指示如下: 第一个参数:每个周期毫秒执行的操作(执行 TimerTask 类或其扩展的运行函数) 第二个参数:定时器必须启动的时间。在这种情况下,它在调用 schedule 函数时启动。以下示例表示调用 schedule 函数后的 1 秒:timer.schedule(new Tasker(),1000,period); 第三个参数:Tasker.run() 函数的一次调用与以下调用之间的毫秒数。

我希望你理解这个微教程:)。如果您有任何问题,请询问更详细的信息!

亲切的问候!

于 2011-08-31T07:58:22.813 回答
4

好吧,下面的代码显示了一个带有 JTextArea 和一个 JButton 的 JFrame。当按钮被点击时,Timer 将事件重复发送(它们之间有第二个延迟)到与按钮相关的 actionListener,该按钮会在当前时间附加一行。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;


public class TimerTest extends JFrame implements ActionListener{

    private static final long serialVersionUID = 7416567620110237028L;
    JTextArea area;
    Timer timer;
    int count; // Counts the number of sendings done by the timer
    boolean running; // Indicates if the timer is started (true) or stopped (false)

    public TimerTest() {
        super("Test");
        setBounds(30,30,500,500);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(null);

        area = new JTextArea();
        area.setBounds(0, 0, 500, 400);
        add(area);

        JButton button = new JButton("Click Me!");
        button.addActionListener(this);
        button.setBounds(200, 400, 100, 40);
        add(button);

        // Initialization of the timer. 1 second delay and this class as ActionListener
        timer = new Timer(1000, this);
        timer.setRepeats(true); // Send events until someone stops it
        count = 0; // in the beginning, 0 events sended by timer
        running = false;
        System.out.println(timer.isRepeats());
        setVisible(true); // Shows the frame
    }

    public void actionPerformed(ActionEvent e) {
        if (! running) {
            timer.start();
            running = true;
        }
        // Writing the current time and increasing the cont times
        area.append(Calendar.getInstance().getTime().toString()+"\n");
        count++;
        if (count == 10) {
            timer.stop();
            count = 0;
            running = false;
        }
    }

    public static void main(String[] args) {
        // Executing the frame with its Timer
        new TimerTest();
    }
}

好吧,这段代码是如何使用 javax.swig.Timer 对象的示例。与问题的具体情况有关。停止计时器的 if 语句必须改变,而且很明显,actionPerformed 的动作。以下片段是解决方案 actionPerformed 的骨架:

public void actionPerformed(ActionEvent e) {
    if (e.getComponent() == myDealerComponent()) {
    // I do this if statement because the actionPerformed can treat more components
        if (! running) {
            timer.start();
            runnig = true;
        }
        // Hit a card if it must be hitted
        switch (getJBTable(JB.total, JB.aces > 0)) {
          case 0:
              JB.hit();
              break;
          case 1:
              break done;
          case 2:
              JB.hit();
              JB.bet *= 2;
              break done;
        }
        if (JB.total >= 21) { // In this case we don't need count the number of times, only check the JB.total 21 reached
            timer.stop()
            running = false;
        }

    }
}

恕我直言,这解决了问题,现在@user920769 必须考虑将 actionListener 和启动/停止条件放在哪里......

@kleopatra:感谢您向我展示了这个计时器类的存在,我对此一无所知,这太棒了,使许多任务成为可能进入摇摆应用程序:)

于 2011-08-31T14:50:55.723 回答
3

我认为在本教程中很清楚如何使用定时器来实现你想要的,而不必处理线程。

于 2011-08-31T04:52:10.290 回答