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

重启游戏后游戏速度与流星下落速率不一致问题求助

问题分析与解决

核心问题原因

  1. 多线程并发冲突:
    旧游戏线程的循环条件依赖成员变量gameLoopThread != null,启动新线程时,gameLoopThread会被立刻赋值为新线程实例,旧线程的循环条件依然为true,不会因为interrupt()而立刻退出。最终导致多个游戏循环线程同时运行,CPU资源被抢占,游戏的update和渲染逻辑被重复执行,视觉上表现为速度变慢。

  2. 重复注册KeyListener:
    resetGame方法中每次都调用addKeyListener(handler),导致同一个KeyHandler被多次注册,按键事件会被多次触发处理,可能间接影响输入响应和游戏逻辑的稳定性。

修复方案

1. 修复线程退出逻辑

修改游戏循环的退出条件,让旧线程能正确响应中断并退出:

@Override
public void run() {
    double drawInterval = (double) 1000000000 / FPS;
    double delta = 0;
    long lastTime = System.nanoTime();
    long currentTime;

    // 改为检查当前线程是否被中断,而非依赖gameLoopThread变量
    while (!Thread.currentThread().isInterrupted()) {
        currentTime = System.nanoTime();
        delta += (currentTime - lastTime) / drawInterval;
        lastTime = currentTime;

        if (delta >= 1) {
            if (!gameOver) { // 游戏结束后不再更新逻辑
                update();
                checkCollisions();
            }
            repaint();
            delta--;
        }

        if (gameOver) {
            displayGameOver();
            break;
        }
    }
}

同时修改startGameLoopThread方法,确保旧线程被彻底中断:

public void startGameLoopThread() {
    if (gameLoopThread != null && gameLoopThread.isAlive()) {
        gameLoopThread.interrupt();
        try {
            // 等待旧线程退出,避免并发问题
            gameLoopThread.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    gameLoopThread = new Thread(this);
    gameLoopThread.start();
}

2. 移除重复的KeyListener注册

在resetGame方法中删除addKeyListener(handler)这一行,组件在构造函数中已经注册过一次,重复注册会导致事件重复触发:

public void resetGame() {
    gameOver = false;
    meteors.clear();
    generateMeteors();
    handler.resetFighterJetMovement();
    fighterJet = new FighterJet(300, 500, 8);
    // 移除这一行:addKeyListener(handler);
    requestFocusInWindow();
    startGameLoopThread();
}

3. 优化displayGameOver中的线程处理

确保游戏结束时线程被正确中断,避免残留:

public void displayGameOver() {
    if (gameOver && !Thread.currentThread().isInterrupted()) {
        Thread.currentThread().interrupt();
        GameOver gameOverScreen = new GameOver(gameWindow, menu,this);
        gameWindow.getContentPane().removeAll();
        gameWindow.add(gameOverScreen);
        gameWindow.pack();
    }
}

额外建议

  • 游戏逻辑中的update和checkCollisions应该放在游戏未结束的判断内,避免游戏结束后还执行不必要的逻辑。
  • 可以考虑使用Swing Timer替代手动线程管理,Swing组件本身是线程不安全的,使用Timer能更好地适配Swing的事件调度线程,减少并发问题。

内容的提问来源于stack exchange,提问作者CAKE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:21:16