【问题标题】:How to change AnimationTimer speed?如何改变 AnimationTimer 的速度?
【发布时间】:2015-07-20 17:04:24
【问题描述】:

我将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;
    }
}

【问题讨论】:

    标签: java animation timer javafx


    【解决方案1】:
    new AnimationTimer() {
    int frameCount = 0;
            @Override
            public void handle(long currentNanoTime) {
    
                if (frameCount % 2 == 0) {
                 // 30 fps ?
               }         
               frameCount++;
    }
    

    可能有点老套,但可以完成工作

    【讨论】:

      【解决方案2】:

      由于我已经编写了代码,并且 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();
      
      }
      

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

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

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

      AnimationTimerExt timer = new AnimationTimerExt(100) {
      
          @Override
          public void handle() {
      
              System.out.println( System.currentTimeMillis());
      
          }
      };
      
      timer.start();
      

      另外,一遍又一遍地加载图片并不是最好的选择。如果你想做动画,我建议你看看 Mike 的关于 Creating a Sprite Animation with JavaFX 的博客。

      【讨论】:

        【解决方案3】:

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

        传递给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;
            }
        }
        

        【讨论】:

        • 更多关于使用AnimationTimer的想法,我推荐阅读thisthis
        • 如果handle 以固定的速率被调用,比如每16ms左右,这种技术不会通过在16、32、16、16、32ms等处进行更新而引入抖动吗?
        • @StevensMiller 是的,在这种情况下它会影响平滑度(轻微)。我之前评论中的链接详细讨论了可能的解决方案。目前还不清楚为什么 OP 想要将其限制在 JavaFX 工具包的“自然”帧渲染速率之外。
        • 很抱歉,我看不出这些链接如何解决这个问题。这是 Java 的一个主要问题,AFAIK 实际上并不允许真正的 vsync。其他人说 AnimationTimer 提供了 vsync,但我的实验很容易证明这一点。同样,页面翻转(有助于防止撕裂)是另一种广泛提出的非解决方案,作为实现垂直同步的一种方式。诚然,OP 是在追求别的东西,但是很多这些问题归结为无法同步锁定到刷新。你知道方法吗?
        • @PhilFreihofner 博客似乎不见了,但相关的代码仓库是 here
        猜你喜欢
        • 2018-10-24
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 2013-03-25
        • 2018-12-12
        • 1970-01-01
        • 2018-12-09
        • 1970-01-01
        相关资源
        最近更新 更多