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 */
关键细节说明
- 遍历集合用副本/迭代器:直接在遍历原集合时删除元素会触发
ConcurrentModificationException,所以高亮时用new ArrayList<>(blocks)创建副本,消行时用迭代器删除。 - PauseTransition的作用:它是JavaFX动画API的一部分,会在后台计时,时间到了自动在UI线程执行
onFinished里的逻辑,完全符合JavaFX的线程安全规则。 - 模型与UI同步:下移时记得同时更新
BlockUnit的模型数据(setY)和UI控件的位置(setLayoutY),避免后续逻辑出错。
内容的提问来源于stack exchange,提问作者lucas
相关产品推荐
相关产品推荐

