如何在javaFX中使用KeyPress事件获得流畅的动画?

时间:2014-01-24 11:28:44

标签: animation javafx javafx-2 javafx-8

我正在尝试在JavaFX中实现矩形形状的LEFT RIGHT移动。以下是我的代码:

public void start(Stage primaryStage) throws Exception {
    AnchorPane ancPane = new AnchorPane();      
    final Rectangle rect = new Rectangle();
    rect.setHeight(50);
    rect.setWidth(50);
    ancPane.getChildren().add(rect);
    Scene scene = new Scene(ancPane, 400, 200, Color.GREEN); 
    primaryStage.setScene(scene);
    primaryStage.show();


    scene.setOnKeyPressed(new EventHandler<KeyEvent>() {

        @Override
        public void handle(KeyEvent keyEvent) {
            System.out.println("hello");

            if(keyEvent.getCode().toString() == "RIGHT"){
                System.out.println("Move Right");
                TranslateTransition translateTransitionRight = new TranslateTransition();
                translateTransitionRight.setDuration(Duration.millis(200));
                translateTransitionRight.setNode(rect);
                translateTransitionRight.setFromX(rect.getTranslateX());
                translateTransitionRight.setToX(rect.getTranslateX()+30);
                translateTransitionRight.play();
            }

            if(keyEvent.getCode().toString() == "LEFT"){
                System.out.println("Move Left");
                TranslateTransition translateTransitionRight = new TranslateTransition();
                translateTransitionRight.setDuration(Duration.millis(200));
                translateTransitionRight.setNode(rect);
                translateTransitionRight.setFromX(rect.getTranslateX());
                translateTransitionRight.setToX(rect.getTranslateX()-30);
                translateTransitionRight.play();
            }               
        }
    });

}

这里当我连续按下LEFT / RIGHT键时(即我没有释放键,我按住它一段时间)矩形移动但不连续。动画开始后,它会暂停一小段时间。暂停后,动画继续顺利进行。

如何摆脱使用KeyEvents暂停动画?

1 个答案:

答案 0 :(得分:3)

我会使用AnimationTimer来移动矩形,只需更新一个表示按下键或释放键的速度的属性:

final Rectangle rect = ... ;

final double rectangleSpeed = 100 ; // pixels per second
final double minX = 0 ;
final double maxX = 800 ; // whatever the max value should be.. can use a property and bind to scene width if needed...
final DoubleProperty rectangleVelocity = new SimpleDoubleProperty();
final LongProperty lastUpdateTime = new SimpleLongProperty();
final AnimationTimer rectangleAnimation = new AnimationTimer() {
  @Override
  public void handle(long timestamp) {
    if (lastUpdateTime.get() > 0) {
      final double elapsedSeconds = (timestamp - lastUpdateTime.get()) / 1_000_000_000.0 ;
      final double deltaX = elapsedSeconds * rectangleVelocity.get();
      final double oldX = rect.getTranslateX();
      final double newX = Math.max(minX, Math.min(maxX, oldX + deltaX));
      rect.setTranslateX(newX);
    }
    lastUpdateTime.set(timestamp);
  }
};
rectangleAnimation.start();

scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
  @Override
  public void handle(KeyEvent event) {
    if (event.getCode()==KeyCode.RIGHT) { // don't use toString here!!!
      rectangleVelocity.set(rectangleSpeed);
    } else if (event.getCode() == KeyCode.LEFT) {
      rectangleVelocity.set(-rectangleSpeed);
    }
  }
});

scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
  @Override
  public void handle(KeyEvent event) {
    if (event.getCode() == KeyCode.RIGHT || event.getCode() == KeyCode.LEFT) {
      rectangleVelocity.set(0);
    }
  }
});

更新:

每次JavaFX机制渲染帧时,AnimationTimer都会执行一次handle方法。传递给handle方法的long是渲染帧的时间戳,以纳秒为单位。

这种方式的工作方式是我们跟踪上次更新时间。 handle(...)方法计算自上次更新以来经过的时间,将其乘以矩形的速度,并以该量更新矩形的translateX。 AnimationTimer始终在运行,但最初速度设置为零,因此矩形不会移动。

keyPressed处理程序只是将速度改变为:如果向右移动则为正值,如果向左移动则为负值。 keyReleased处理程序将速度设置回零。