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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:40:27