Animation 如何在javaFX中使用按键事件获得平滑动画?

Animation 如何在javaFX中使用按键事件获得平滑动画?,animation,javafx,javafx-2,javafx-8,Animation,Javafx,Javafx 2,Javafx 8,我试图在JavaFX中实现矩形形状的左右移动。下面是我的代码: public void start(Stage primaryStage) throws Exception { AnchorPane ancPane = new AnchorPane(); final Rectangle rect = new Rectangle(); rect.setHeight(50); rect.setWidth(50); ancPane.getChildr

我试图在JavaFX中实现矩形形状的左右移动。下面是我的代码:

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();
            }               
        }
    });

}
public void start(Stage primaryStage)引发异常{
Ancorpane=新的Ancorpane();
最终矩形rect=新矩形();
直线设置高度(50);
直线设置宽度(50);
ancPane.getChildren().add(rect);
场景=新场景(窗格,400,200,颜色.绿色);
初级阶段。场景(场景);
primaryStage.show();
scene.setOnKeyPressed(新的EventHandler(){
@凌驾
公共无效句柄(KeyEvent KeyEvent){
System.out.println(“你好”);
if(keyEvent.getCode().toString()=“右”){
System.out.println(“向右移动”);
TranslateTransition translateTransitionRight=新的TranslateTransition();
translateTransitionRight.setDuration(Duration.millis(200));
translateTransitionRight.setNode(rect);
setFromX(rect.getTranslationRight());
translateTransitionRight.setToX(rect.getTranslateX()+30);
translateTransitionRight.play();
}
if(keyEvent.getCode().toString()=“左”){
System.out.println(“向左移动”);
TranslateTransition translateTransitionRight=新的TranslateTransition();
translateTransitionRight.setDuration(Duration.millis(200));
translateTransitionRight.setNode(rect);
setFromX(rect.getTranslationRight());
translateTransitionRight.setToX(rect.getTranslateX()-30);
translateTransitionRight.play();
}               
}
});
}
在这里,当我连续按左/右键时(即,我没有释放键,我按住它几次),矩形移动,但不是连续移动。动画开始后,它会暂停一小部分时间。暂停后,动画将平稳继续


如何使用KeyEvents消除动画暂停?

我会使用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);
    }
  }
});
最终矩形rect=;
最终双矩形速度=100;//每秒像素数
最终双最小值=0;
最终双精度最大值=800;//无论最大值应该是多少。。如果需要,可以使用属性并绑定到场景宽度。。。
最终DoubleProperty矩形速度=新的SimpleDoubleProperty();
final LongProperty lastUpdateTime=新的SimpleLongProperty();
最终AnimationTimer rectangleAnimation=新AnimationTimer(){
@凌驾
公共无效句柄(长时间戳){
if(lastUpdateTime.get()>0){
final double-elapsedSeconds=(timestamp-lastUpdateTime.get())/1\u 000\u 000.0;
final double deltaX=elapsedSeconds*rectangleVelocity.get();
final double oldX=rect.getTranslateX();
最终双精度newX=Math.max(minX,Math.min(maxX,oldX+deltaX));
rect.setTranslateX(newX);
}
lastUpdateTime.set(时间戳);
}
};
矩形动画;
scene.setOnKeyPressed(新的EventHandler(){
@凌驾
公共无效句柄(KeyEvent事件){
如果(event.getCode()==KeyCode.RIGHT){//不要在这里使用toString!!!
矩形速度。设置(矩形速度);
}else if(event.getCode()==KeyCode.LEFT){
矩形速度。设置(-矩形速度);
}
}
});
scene.setOnKeyReleased(新的EventHandler(){
@凌驾
公共无效句柄(KeyEvent事件){
if(event.getCode()==KeyCode.RIGHT | | event.getCode()==KeyCode.LEFT){
矩形速度设置(0);
}
}
});
更新:

每次通过JavaFX机制渲染帧时,都会执行其handle方法一次。传递到handle方法中的long是渲染帧的时间戳,单位为纳秒

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


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

这种方法的一个很好(但可能不明显)的特点是,您可以通过编程完全控制矩形的速度;它不是由操作系统级别的设置(如键盘重复率等)决定的。嗨,詹姆斯,当我交替快速按左/右键时,动画开始时仍然有一些暂停效果。另外,请您提供一些关于您在这里实现的逻辑的解释。通过一些分析,我可以理解逻辑。此外,我还对scene.setOnKeyReleased()进行了一些小修改,仅当释放左/右键时,才将rectangleVelocity设置为0,否则会在动画中产生暂停效果。谢谢。添加了一些解释,以防其他人需要。