【问题标题】:How to get smooth animation with KeyPress event in javaFX?如何在 javaFX 中使用 KeyPress 事件获得流畅的动画?
【发布时间】:2014-01-24 11:28:44
【问题描述】:

我正在尝试在 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();
            }               
        }
    });

}

在这里,当我连续按左/右键(即我没有松开键,我按住它一段时间)时,矩形移动但不是连续的。它在动画开始后暂停一小部分时间。暂停后动画继续流畅。

如何通过 KeyEvents 摆脱这种动画暂停?

【问题讨论】:

    标签: animation javafx javafx-2 javafx-8


    【解决方案1】:

    我会使用 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 方法的 long 是渲染帧的时间戳,以纳秒为单位。

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

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

    【讨论】:

    • 这种方法的一个不错(但可能并不明显)的特点是您可以完全以编程方式控制矩形的速度;它不是由操作系统级别的设置决定的,例如键盘重复率等。
    • 嗨,James,当我快速交替按 LEFT/RIGHT 键时,动画开始时仍有一些暂停效果。您还可以提供一些关于您在此处实现的逻辑的解释。
    • 通过一些分析我可以理解逻辑。此外,我在 scene.setOnKeyReleased() 中进行了小修改,仅在释放 LEFT/RIGHT 键时将 rectangleVelocity 设置为 0,否则会导致动画暂停效果。谢谢。
    • 添加了一些解释以防其他人需要。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多