java 如何更改 AnimationTimer 速度?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30146560/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:33:10  来源:igfitidea点击:

How to change AnimationTimer speed?

javaanimationtimerjavafx

提问by Alyona

I use AnimationTimerfor several tasks like animation with changing pictures and ProgressIndicatoranimation. To achieve needed speed I put thread to sleep, but when several animations are running simultaneously they affect each others speed. Is there any other way to change speed of AnimationTimer? Code sample:

AnimationTimer用于多个任务,例如带有不断变化的图片和ProgressIndicator动画的动画。为了达到所需的速度,我让线程进入睡眠状态,但是当多个动画同时运行时,它们会影响彼此的速度。有没有其他方法可以改变速度AnimationTimer?代码示例:

private void initialize() {
 programButtonAnimation=new AnimationTimer(){
            @Override
            public void handle(long now) {
                    showClockAnimation();
            }
        };
 programButtonAnimation.start();
}

private void showClockAnimation(){
    String imageName = "%s_"+"%05d"+".%s";
    String picturePath="t093760/diploma/view/styles/images/pink_frames/"+String.format( imageName,"pink" ,frameCount,"png");
    programButton.setStyle("-fx-background-image:url('"+picturePath+"')");
    frameCount++;
    try {
        Thread.sleep(28);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    if(frameCount>=120){
        programButtonAnimation.stop();
        frameCount=0;
    }
}

回答by James_D

The AnimationTimer's handlemethod is invoked once for each frame that is rendered, on the FX Application Thread. You should never block that thread, so do not call Thread.sleep(...)here.

所述AnimationTimerhandle方法被调用一次,所呈现,在FX应用程序线程的每个帧。你永远不应该阻塞那个线程,所以不要Thread.sleep(...)在这里调用。

The parameter passed to the handle(...)method is a timestamp, in nanoseconds. So if you want to throttle updates so they don't happen more than once every, say 28 milliseconds, you can use this to do so:

传递给该handle(...)方法的参数是一个时间戳,以纳秒为单位。因此,如果您想限制更新,使更新不会超过一次,例如 28 毫秒,您可以使用它来执行此操作:

private void initialize() {
 programButtonAnimation=new AnimationTimer(){

            private long lastUpdate = 0 ;
            @Override
            public void handle(long now) {
                    if (now - lastUpdate >= 28_000_000) {
                        showClockAnimation();
                        lastUpdate = now ;
                    }
            }
        };
 programButtonAnimation.start();
}

private void showClockAnimation(){
    String imageName = "%s_"+"%05d"+".%s";
    String picturePath="t093760/diploma/view/styles/images/pink_frames/"+String.format( imageName,"pink" ,frameCount,"png");
    programButton.setStyle("-fx-background-image:url('"+picturePath+"')");
    frameCount++;
    if(frameCount>=120){
        programButtonAnimation.stop();
        frameCount=0;
    }
}

回答by Roland

Since I already wrote the code and James_D was faster with informing you about you blocking the UI, I still like to add that if you have multiple AnimationTimers of different timings you should create a dedicated class for that. If each of them runs at a different speed, you could implement it like that:

由于我已经编写了代码并且 James_D 更快地通知您您阻止了 UI,我仍然想补充一点,如果您有多个不同时间的 AnimationTimer,您应该为此创建一个专用类。如果它们中的每一个都以不同的速度运行,您可以像这样实现它:

import javafx.animation.AnimationTimer;

public abstract class AnimationTimerExt extends AnimationTimer {

    private long sleepNs = 0;

    long prevTime = 0;

    public AnimationTimerExt( long sleepMs) {
        this.sleepNs = sleepMs * 1_000_000;
    }

    @Override
    public void handle(long now) {

         // some delay
        if ((now - prevTime) < sleepNs) {
            return;
        }

        prevTime = now;

        handle();
    }

    public abstract void handle();

}

Which means that the handle() method is invoked at least after sleepMs milliseconds have passed.

这意味着至少在经过 sleepMs 毫秒后调用 handle() 方法。

Or you change the parameter and specify the fps, whatever you need.

或者您可以更改参数并指定 fps,无论您需要什么。

You can use the above code like this:

您可以像这样使用上面的代码:

AnimationTimerExt timer = new AnimationTimerExt(100) {

    @Override
    public void handle() {

        System.out.println( System.currentTimeMillis());

    }
};

timer.start();

Also, loading the picture over and over again is not the best choice. If you'd like to do animations, I suggest you take a look at Mike's Blog about Creating a Sprite Animation with JavaFX.

此外,一遍又一遍地加载图片也不是最好的选择。如果您想做动画,我建议您查看 Mike 的关于使用 JavaFX 创建 Sprite 动画的博客。

回答by Progreg

new AnimationTimer() {
int frameCount = 0;
        @Override
        public void handle(long currentNanoTime) {

            if (frameCount % 2 == 0) {
             // 30 fps ?
           }         
           frameCount++;
}

might be a bit hacky but gets the job done

可能有点hacky但可以完成工作