javaFX - 无需创建新线程即可创建平滑动画

时间:2016-12-24 14:43:48

标签: java animation javafx

我的javaFX项目中有一辆汽车,当按下SPACE时,汽车(Node)的位置应该改变(汽车应该平稳地跳跃)。所以我使用了一个事件处理程序来调用名为moveUp()

的方法
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent event) {
            switch (event.getCode())
            {
                case SPACE:
                    moveUp();
                    break;
            }
        }
    });

这会创建一个新的线程,其中汽车的速度改变10次,间隔为75毫秒。

private void moveUp() {
   new Thread(new Runnable() {
       @Override
       public void run() {
           carSpeed = 10;
           for(;carSpeed>=0;carSpeed--)
           {
               try {
                   Thread.currentThread().sleep(75);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               carPosition_X+=carSpeed;
               carPosition_Y-=carSpeed;
               car.relocate(carPosition_X,carPosition_Y);
           }
           for(carSpeed=0;carSpeed<=10;carSpeed++)
           {
               try {
                   Thread.currentThread().sleep(75);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               carPosition_X+=carSpeed;
               carPosition_Y+=carSpeed;
               car.relocate(carPosition_X,carPosition_Y);
           }
       }
   }).start();
}

这段代码是这样做的(按一次SPACE并跳车): enter image description here

如果我不使用不同的线程,GUI线程将被冻结,如果我不使用Thread.sleep(),汽车将突然跳转(不顺利)。这段代码做得很好。但我了解到thread.start()并不能保证线程的立即执行。我怎样才能保证立即执行?

1 个答案:

答案 0 :(得分:1)

我建议留在FX应用程序主题并使用类AnimationTimer。这是一个平滑跳跃的简短演示:

private void moveUp() {
        new AnimationTimer() {
            long startTime = -1;
            double initCarPosition_Y;                

            @Override
            public void handle(long now) {
                if(startTime == -1){
                    startTime = now;
                    initCarPosition_Y = carPosition_Y;
                    carSpeedX = 3d;
                    carSpeedY = -15d;                                   
                }                   

                double time = (now - startTime) / 1E9d;
                carPosition_X += carSpeedX * time;  
                carPosition_Y += carSpeedY * time;
                if(carSpeed > 0 && initCarPosition_Y <= carPosition_Y){
                    carPosition_Y = initCarPosition_Y;
                    stop();
                }
                carSpeedY += 0.8d * time; //gravity

                car.relocate(carPosition_X, carPosition_Y);                 
            }
        }.start();
}

这种方法可让您全面直接控制每一帧中发生的事情。但是,javaFX还提供高级动画类,包括预定义的插值器和转换。适合替代方法的可以是以下类别:

  • PathTransition:允许您定义给定节点动画的点和曲线。
  • TimeLine:允许您根据节点位置等属性定义任意动画关键帧。

请注意,当您想为像汽车这样的用户控制的演员设置动画时,通常使用这些高级课程可能会变得具有挑战性。这些类都需要一段精确的持续时间才能使动画持续。例如,只要按下特定键就想要翻译节点,就不能事先知道动画的持续时间。