如何在俄罗斯轮盘赌Swing程序中使用Swing Timer实现暂停效果?
解决Swing Timer在俄罗斯轮盘赌游戏中的使用问题
我太懂你这种困扰了——之前用Thread.sleep()的时候,界面直接卡死,图片根本来不及显示,对吧?这是因为Swing是单线程UI模型,所有界面更新都在事件调度线程(EDT)里完成,Thread.sleep()会阻塞EDT,导致界面完全没法刷新,自然看不到图片。
Swing Timer就是为这种场景设计的:它在EDT里调度任务,不会阻塞界面,还能精准控制延迟时间。下面我给你重构代码,解决这个问题:
核心思路
原来的for循环会瞬间跑完所有轮次,中间的图片根本没机会显示。我们需要把游戏拆成分阶段执行,用Timer来触发每一轮的逻辑,每轮存活后等待几秒再进入下一轮。
修改后的完整代码
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.concurrent.atomic.AtomicInteger; public class YourGameClass implements ActionListener { // 假设你的类实现了ActionListener private JFrame frame; private JLabel label1, label2; @Override public void actionPerformed(ActionEvent e) { PanelCasino panel = (PanelCasino) e.getSource(); // 修正获取panel的方式,根据你的实际情况调整 frame = new JFrame(); // 1. 提前生成子弹的固定位置(俄罗斯轮盘的子弹位置是固定的,不是每轮随机) final int bulletPosition = (int)(Math.random() * 6 + 1); // 2. 用原子整数跟踪当前轮次(lambda里需要线程安全的变量) AtomicInteger currentRound = new AtomicInteger(0); // 3. 封装每一轮的配置,避免重复的if-else record RoundConfig( int randomRangeMax, // 本轮随机数的最大值 boolean isOtherPlayer,// 本轮轮到对方还是自己 String aliveImage, // 存活时显示的图片 String deadImage, // 死亡时显示的图片 String aliveText, // 存活时的文本 String deadText, // 死亡时的文本 int betChange // 输赢对应的赌注变化(+赢,-输) ) {} // 定义6轮游戏的配置 RoundConfig[] rounds = { new RoundConfig(6, true, "gun1.jpg", "gun3.jpg", "The other player lives...", "The other player got sprayed up!", panel.bet), new RoundConfig(5, false, "gun2.jpg", "gun4.jpg", "You live...", "You got sprayed up! Rip!", -panel.bet), new RoundConfig(4, true, "gun1.jpg", "gun3.jpg", "The other player lives...", "The other player got sprayed up!", panel.bet), new RoundConfig(3, false, "gun2.jpg", "gun4.jpg", "You live...", "You got sprayed up! Rip!", -panel.bet), new RoundConfig(2, true, "gun1.jpg", "gun3.jpg", "The other player lives...", "The other player got sprayed up!", panel.bet), new RoundConfig(1, false, null, "gun4.jpg", null, "You got sprayed up! Rip!", -panel.bet) // 最后一轮必中 }; // 4. 创建Swing Timer,每2秒触发一次下一轮(可根据需求调整延迟时间,单位毫秒) Timer gameTimer = new Timer(2000, null); gameTimer.addActionListener(timerEvent -> { int current = currentRound.getAndIncrement(); if (current >= rounds.length) { gameTimer.stop(); // 所有轮次结束,停止计时器 return; } RoundConfig currentConfig = rounds[current]; int randomNum = (int)(Math.random() * currentConfig.randomRangeMax + 1); // 判断本轮是否命中子弹 boolean isHit = (current == 5) || (bulletPosition == randomNum); if (isHit) { // 死亡逻辑:显示死亡图片和文本,更新赌注,停止游戏 label2.setIcon(new ImageIcon(currentConfig.deadImage)); label1.setText(currentConfig.deadText); panel.total += currentConfig.betChange; gameTimer.stop(); } else { // 存活逻辑:显示存活图片和文本,等待Timer触发下一轮 label2.setIcon(new ImageIcon(currentConfig.aliveImage)); label1.setText(currentConfig.aliveText); } // 更新界面显示 panel.label3.setText(String.valueOf(panel.total)); panel.revalidate(); panel.repaint(); // 强制刷新界面,确保图片和文本及时显示 }); // 第一轮立即执行,不需要等待延迟 gameTimer.setInitialDelay(0); gameTimer.start(); } }
关键细节说明
- 固定子弹位置:原来的代码每轮都生成新的
num,这不符合俄罗斯轮盘的逻辑——子弹位置是固定的,每次只是随机选择发射位置,所以我们提前生成bulletPosition,整个游戏过程中保持不变。 - 轮次配置封装:用
record把每轮的参数打包,避免了大量重复的if-else,代码更易维护。 - Timer的工作方式:Timer的
actionPerformed方法在EDT中执行,所以所有UI更新都是安全的,不会出现线程问题。 - 延迟控制:设置2000毫秒(2秒)的延迟,你可以根据需要调整这个数值,比如改成1500就是1.5秒。
- 界面刷新:每次更新后调用
repaint()确保界面及时刷新,避免图片或文本不显示的问题。
额外注意事项
- 确保图片路径正确:如果图片放在项目的资源文件夹里,可能需要用
getClass().getResource("gun1.jpg")来获取路径,避免找不到图片的问题。 - 避免重复启动Timer:如果用户多次点击按钮,要确保之前的Timer已经停止,不然会出现多个Timer同时运行的混乱情况。
内容的提问来源于stack exchange,提问作者Rakesh Pillai
相关产品推荐
相关产品推荐

