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

JavaFX开发:如何实现两次UI事件更新间的延迟(俄罗斯方块消行场景)

JavaFX俄罗斯方块:实现消行前高亮延迟的正确方式

别用线程、Task或者while循环硬卡延迟了,JavaFX自带专门处理UI延迟的工具——PauseTransition,它不会阻塞UI线程,能完美实现你要的“高亮半秒后消行”效果。

问题根源

你之前的几种尝试都踩了JavaFX的UI线程规则:

  • while循环直接阻塞UI线程,导致高亮还没渲染出来就执行了消行,视觉上看不到效果;
  • 手动新建线程如果没正确同步,容易引发集合操作异常,而且没必要;
  • Task更适合后台计算任务,用来做单纯延迟有点冗余。

修改后的代码实现

直接替换你原来的消行逻辑部分:

/* some code above */
if(isFilledRow) {
    // 1. 先高亮当前满行的所有方块(优化遍历逻辑)
    for (BlockUnit bu : new ArrayList<>(blocks)) {
        if (bu.getY() == i) {
            bu.getShape().setFill(Color.BROWN);
        }
    }

    // 2. 创建500毫秒的延迟任务
    PauseTransition delay = new PauseTransition(Duration.millis(500));
    delay.setOnFinished(event -> {
        // 3. 延迟结束后执行消行
        // 用迭代器安全删除集合元素,避免索引越界
        Iterator<BlockUnit> iterator = blocks.iterator();
        while (iterator.hasNext()) {
            BlockUnit bu = iterator.next();
            if (bu.getY() == i) {
                root.getChildren().remove(bu.getShape());
                iterator.remove();
            }
        }

        // 4. 处理上方所有方块下移一行
        // 这里假设blockSize是你定义的单个方块的边长(比如20)
        for (BlockUnit bu : blocks) {
            if (bu.getY() < i) {
                bu.setY(bu.getY() + 1); // 更新模型数据
                bu.getShape().setLayoutY(bu.getShape().getLayoutY() + blockSize); // 同步UI位置
            }
        }
    });

    // 启动延迟任务
    delay.play();
}
/* some code below */

关键细节说明

  1. 遍历集合用副本/迭代器:直接在遍历原集合时删除元素会触发ConcurrentModificationException,所以高亮时用new ArrayList<>(blocks)创建副本,消行时用迭代器删除。
  2. PauseTransition的作用:它是JavaFX动画API的一部分,会在后台计时,时间到了自动在UI线程执行onFinished里的逻辑,完全符合JavaFX的线程安全规则。
  3. 模型与UI同步:下移时记得同时更新BlockUnit的模型数据(setY)和UI控件的位置(setLayoutY),避免后续逻辑出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:15:12