You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:33:15