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

Java Android Studio俄罗斯方块游戏暂停/启动按钮异常问题求助

解决Android俄罗斯方块暂停/重启异常的问题

嘿,作为Java新手碰到这种游戏线程控制的问题太正常啦,我来帮你一步步捋清楚问题根源和解决办法~

问题核心原因

你现在的写法有两个致命问题:

  1. 主线程阻塞:如果你的pause()方法是在Android主线程(UI线程)里执行的,那里面的while循环加sleep()直接会卡死主线程——Android主线程是用来处理UI交互、刷新的,一旦被耗时操作阻塞,不仅游戏逻辑停摆,连你的重启按钮点击事件都可能得不到响应。
  2. 变量可见性问题:你用来控制暂停的布尔变量(比如ps)如果没加volatile修饰,在多线程环境下,游戏线程可能看不到主线程修改的变量值,导致重启时明明把布尔值设为false,游戏线程还一直停在暂停循环里。

正确的实现方案

我们需要把游戏逻辑放到独立的子线程里,用线程安全的方式控制暂停和重启,避免阻塞主线程。

1. 定义线程和控制变量

先定义一个带volatile修饰的暂停标记,还有游戏线程对象:

// volatile保证多线程间变量的可见性,子线程能立刻看到主线程修改的值
private volatile boolean isGamePaused = false;
private Thread gameLogicThread;

2. 编写游戏逻辑的线程方法

把原来的游戏循环放到子线程里,用wait()/notify()来控制暂停和唤醒,代替空循环sleep:

private void runGameLoop() {
    while (!Thread.currentThread().isInterrupted()) {
        // 暂停逻辑:如果标记为暂停,就进入等待状态
        while (isGamePaused) {
            try {
                // 用synchronized保证线程安全,wait()会释放锁,避免空耗CPU
                synchronized (this) {
                    wait();
                }
            } catch (InterruptedException e) {
                // 如果线程被中断,直接退出循环,避免资源泄漏
                Thread.currentThread().interrupt();
                break;
            }
        }

        // ----------------------
        // 这里写你的游戏核心逻辑:
        // 方块下落、碰撞检测、得分计算等
        // ----------------------

        // 模拟方块下落的间隔(根据你的需求调整时间)
        try {
            Thread.sleep(600);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            break;
        }
    }
}

3. 实现暂停/重启方法

// 暂停游戏
private void pauseGame() {
    isGamePaused = true;
    // 保留你原来的音乐暂停逻辑
    if (music != null) {
        music.pause();
    }
}

// 重启/恢复游戏
private void resumeGame() {
    isGamePaused = false;
    // 唤醒等待的游戏线程
    synchronized (this) {
        notify();
    }
    // 恢复音乐播放
    if (music != null) {
        music.start();
    }
}

4. 启动游戏线程

在游戏初始化或者开始按钮的点击事件里启动子线程:

private void startGame() {
    gameLogicThread = new Thread(this::runGameLoop);
    gameLogicThread.start();
}

5. 销毁时清理线程

记得在Activity销毁时中断游戏线程,防止内存泄漏:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (gameLogicThread != null && gameLogicThread.isAlive()) {
        gameLogicThread.interrupt();
    }
}

额外提醒

  • 永远不要在Android主线程里做while循环加sleep()这种耗时操作,不然一定会触发ANR(应用无响应)弹窗。
  • volatile关键字不能少,它能确保主线程修改的isGamePaused值立刻被游戏线程感知到。
  • 用wait()/notify()比空循环sleep更高效,不会白白消耗CPU资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:05:02