JavaFx 实时刷新

之前想用JavaFx Canvas写个小游戏,在网上找实时刷新的方式。找到用Platform.runLater把渲染插入到JavaFx 图形线程的方法,不过他却用了Thread的sleep函数。我觉得不好,改用了信号量。

我首先定义了一个接口,便于把操作留给使用者自己定义(说白了就是我不想写太多的演示代码):

public interface Updatable {
    void update(double moment);
}

接着就是实时刷新的类:

import javafx.application.Platform;
import java.util.concurrent.Semaphore;

public class Advancer {
    private boolean able;
    private Updatable worker;

    public Advancer(Updatable worker){
        able = false;
        this.worker = worker;
    }

    public final synchronized void advance(Updatable renderer){
        if(able)return;//防止启动多个线程
        able = true;
        new Thread(()->{
            long timer = System.nanoTime();
            Semaphore semaphore = new Semaphore(1);
            while(able)try{
                //计算瞬间时间
                long now = System.nanoTime();
                double moment = (now - timer) * 0.000000001;
                timer = now;
                //处理事务
                worker.update(moment);
                semaphore.acquire();
                Platform.runLater(()->{
                    renderer.update(moment);
                    semaphore.release();
                });
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    //记得熄火,不过线程不会马上退出。
    public final void misfire(){
        able = false;
    }
}

注意:

worker 执行后台每帧的刷新,renderer执行图形界面的刷新。

分析

其实就是启用一个线程,该线程循环地执行:

1.用nanoTime算出每帧的用时。

2.调用worker,并查看信号量。

3.如果信号量已被释放,那么通过Platform.runLater把renderer传递给JavaFx图形线程(执行完renderer后会释放信号量)。

4.回到第1步。

这个过程后台线程起主导作用,并且在把渲染任务交给图形线程后自己可以处理下一帧(即,图形处理当前帧,后台处理下一帧,这个过程可以并行,所以要注意)。

最后那个misfire只是改变了able,让线程自己退出。用完记得熄火。

注意把JavaFx与图形相关的操作放在renderer里。

并且2个线程如果有数据共享需要格外注意。

你可能感兴趣的:(JavaFx 实时刷新)