JavaFX Timeline被锁定在1fps的技术问题求助
JavaFX Timeline 被锁定在1fps的问题解决
核心问题
你对JavaFX Timeline的核心机制理解有误:
- 构造
Timeline时使用的new Timeline(120),参数是循环次数而非帧率,即便后续用setCycleCount(Timeline.INDEFINITE)覆盖了该值,也没解决根本问题; - JavaFX的Timeline是一条线性时间线,所有KeyFrame的时间是相对于时间线起始点的绝对时间,当时间线循环时会从头开始。你添加的三个KeyFrame中最长时间为1秒(FPS统计逻辑),导致整个Timeline的周期被拉到1秒——每过1秒,三个KeyFrame才各触发一次,这就是所有逻辑都仅每秒执行一次的原因。
正确实现方案
游戏循环通常采用最高帧率主循环+内部计数判断的方式,既符合JavaFX的UI线程机制,又能精准控制不同逻辑的触发频率。以下是修改后的代码:
修改后的TickSystem类
package TickSystem; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.event.ActionEvent; import javafx.scene.shape.Rectangle; import javafx.util.Duration; public class TickSystem { private final Timeline gameLoop; public Rectangle r; public int curFrame = 0; public int tick = 0; // 120帧/秒 → 每2帧执行一次60帧/秒的更新逻辑 private static final int UPDATE_INTERVAL = 2; private int frameCounter = 0; public int fps; private int lastFrames = 0; public TickSystem(Rectangle r){ this.r = r; // 主循环以120次/秒运行 Duration frameDuration = Duration.millis(1000.0 / 120); KeyFrame frameKey = new KeyFrame(frameDuration, this::handleFrame); gameLoop = new Timeline(frameKey); gameLoop.setCycleCount(Timeline.INDEFINITE); } public void start(){ gameLoop.play(); } public void pause(){ gameLoop.pause(); } public void stop(){ gameLoop.stop(); } private void handleFrame(ActionEvent ae) { // 120次/秒的绘制逻辑 curFrame++; r.setWidth(curFrame); // 每2帧执行一次60次/秒的更新逻辑 frameCounter++; if (frameCounter >= UPDATE_INTERVAL) { tick++; frameCounter = 0; } // 每秒统计一次FPS(每120帧) if (curFrame - lastFrames >= 120) { fps = curFrame - lastFrames; lastFrames = curFrame; System.out.println("FPS: " + fps); } } }
方案说明
- 用一个以120次/秒运行的主Timeline统一处理所有逻辑,避免多Timeline的时间偏差;
- 通过
frameCounter计数,每2帧触发一次60次/秒的更新逻辑; - 通过帧差值判断,每120帧(1秒)输出一次FPS统计;
- 所有操作都在JavaFX应用线程中执行,符合UI线程安全要求。
备选方案:多Timeline独立处理
如果偏好直观的分逻辑处理,也可以为不同频率的任务创建独立Timeline:
package TickSystem; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.event.ActionEvent; import javafx.scene.shape.Rectangle; import javafx.util.Duration; public class TickSystem { private final Timeline updateTimeline; private final Timeline drawTimeline; private final Timeline fpsTimeline; public Rectangle r; public int curFrame = 0; public int tick = 0; public int fps; private int lastFrames = 0; public TickSystem(Rectangle r){ this.r = r; // 60次/秒的更新逻辑 updateTimeline = new Timeline(new KeyFrame(Duration.millis(1000/60), e -> tick++)); updateTimeline.setCycleCount(Timeline.INDEFINITE); // 120次/秒的绘制逻辑 drawTimeline = new Timeline(new KeyFrame(Duration.millis(1000/120), e -> { curFrame++; r.setWidth(curFrame); })); drawTimeline.setCycleCount(Timeline.INDEFINITE); // 1次/秒的FPS统计 fpsTimeline = new Timeline(new KeyFrame(Duration.seconds(1), e -> { fps = curFrame - lastFrames; lastFrames = curFrame; System.out.println("FPS: " + fps); })); fpsTimeline.setCycleCount(Timeline.INDEFINITE); } public void start(){ updateTimeline.play(); drawTimeline.play(); fpsTimeline.play(); } public void pause(){ updateTimeline.pause(); drawTimeline.pause(); fpsTimeline.pause(); } public void stop(){ updateTimeline.stop(); drawTimeline.stop(); fpsTimeline.stop(); } }
内容的提问来源于stack exchange,提问作者leevmealone
相关产品推荐
相关产品推荐

