Java图片拼图游戏:如何用Thread实现计时统计解谜时长?
嘿,我来给你分享几个用Java实现拼图游戏计时器的实用方案,都是基于Thread相关的思路,完美适配你的开发场景~
方案1:用普通Thread实现基础计时
这个方案直观易懂,适合简单的游戏场景,核心是启动一个独立线程,每秒更新计时并同步到UI。
import javax.swing.*; import java.awt.*; public class PuzzleGame extends JFrame { private JLabel timeDisplay; private Thread timerThread; // 用volatile保证多线程下的可见性 private volatile boolean isTimerRunning = false; private long gameStartTime; private int totalSeconds; public PuzzleGame() { // 初始化UI timeDisplay = new JLabel("00:00", SwingConstants.CENTER); timeDisplay.setFont(new Font("Arial", Font.BOLD, 24)); add(timeDisplay, BorderLayout.NORTH); // 开始游戏按钮 JButton startBtn = new JButton("开始拼图"); startBtn.addActionListener(e -> startGameTimer()); add(startBtn, BorderLayout.SOUTH); setSize(400, 400); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } private void startGameTimer() { if (isTimerRunning) return; isTimerRunning = true; gameStartTime = System.currentTimeMillis(); totalSeconds = 0; timerThread = new Thread(() -> { while (isTimerRunning) { try { Thread.sleep(1000); // 用系统时间计算时长,避免sleep误差累积 totalSeconds = (int) ((System.currentTimeMillis() - gameStartTime) / 1000); String formattedTime = String.format("%02d:%02d", totalSeconds / 60, totalSeconds % 60); // 必须在UI线程更新组件(Swing用EDT) SwingUtilities.invokeLater(() -> timeDisplay.setText(formattedTime)); } catch (InterruptedException ex) { // 线程被中断时退出循环 Thread.currentThread().interrupt(); break; } } }); timerThread.start(); } // 拼图完成时调用此方法停止计时 public void finishGame() { isTimerRunning = false; if (timerThread != null) { timerThread.interrupt(); } JOptionPane.showMessageDialog(this, String.format("恭喜完成!用时:%d秒", totalSeconds)); } public static void main(String[] args) { // Swing必须在EDT启动 SwingUtilities.invokeLater(PuzzleGame::new); } }
方案2:用ScheduledExecutorService实现更可靠的计时
如果想更优雅地管理线程(比如避免手动处理线程启停、中断),可以用Java并发包提供的ScheduledExecutorService,它比普通Thread更稳定,适合复杂一点的场景。
import javax.swing.*; import java.awt.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.Future; public class PuzzleGameExecutor extends JFrame { private JLabel timeDisplay; private ScheduledExecutorService timerExecutor; private Future<?> timerTask; private long gameStartTime; private int totalSeconds; public PuzzleGameExecutor() { timeDisplay = new JLabel("00:00", SwingConstants.CENTER); timeDisplay.setFont(new Font("Arial", Font.BOLD, 24)); add(timeDisplay, BorderLayout.NORTH); JButton startBtn = new JButton("开始拼图"); startBtn.addActionListener(e -> startGameTimer()); add(startBtn, BorderLayout.SOUTH); setSize(400, 400); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } private void startGameTimer() { if (timerExecutor != null && !timerExecutor.isShutdown()) return; gameStartTime = System.currentTimeMillis(); totalSeconds = 0; timerExecutor = Executors.newSingleThreadScheduledExecutor(); // 每秒执行一次计时任务,初始延迟0秒 timerTask = timerExecutor.scheduleAtFixedRate(() -> { totalSeconds = (int) ((System.currentTimeMillis() - gameStartTime) / 1000); String formattedTime = String.format("%02d:%02d", totalSeconds / 60, totalSeconds % 60); SwingUtilities.invokeLater(() -> timeDisplay.setText(formattedTime)); }, 0, 1, TimeUnit.SECONDS); } public void finishGame() { if (timerTask != null) { timerTask.cancel(true); } if (timerExecutor != null) { timerExecutor.shutdown(); } JOptionPane.showMessageDialog(this, String.format("恭喜完成!用时:%d秒", totalSeconds)); } public static void main(String[] args) { SwingUtilities.invokeLater(PuzzleGameExecutor::new); } }
关键注意事项
- UI线程安全:不管用哪种方案,更新UI组件(比如时间标签)必须在Swing的事件调度线程(EDT)或者JavaFX的Application Thread中,否则会出现UI卡顿或异常。Swing用
SwingUtilities.invokeLater(),JavaFX用Platform.runLater()。 - 计时精度:不要单纯用
Thread.sleep(1000)累加秒数,因为系统负载可能导致sleep延迟,用System.currentTimeMillis()计算时间差的方式更准确。 - 资源清理:停止计时时一定要正确中断线程或者关闭Executor,避免内存泄漏。比如方案1中用
interrupt()终止线程,方案2中用shutdown()关闭Executor。 - 暂停功能:如果需要暂停计时,可以在方案1中加一个
isPaused的volatile变量,循环里判断;方案2中可以取消当前任务,暂停时记录暂停时间,恢复时重新计算起始时间。
如果你的游戏用的是JavaFX,只需要把Swing相关的API替换成FX的组件(比如Label代替JLabel),核心计时逻辑完全通用~
内容的提问来源于stack exchange,提问作者S.Sharleen
相关产品推荐
相关产品推荐

