2014-01-24 2 views
2

Я пытаюсь реализовать LEFT RIGHT движение прямоугольной формы в JavaFX. Ниже мой код:Как получить гладкую анимацию с событием KeyPress в 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?

ответ

4

Я хотел бы использовать 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); 
    } 
    } 
}); 

UPDATE:

AnimationTimer выполняет свой метод ручки один раз каждый время, созданное механизмом JavaFX. Длинный проход в метод ручки - это отметка времени рендеринга в наносекундах.

Как это работает, мы отслеживаем последнее время обновления. Метод handle (...) вычисляет прошедшее время с момента последнего обновления, умножает его на скорость прямоугольника и обновляет трансляцию X прямоугольника на эту величину. AnimationTimer всегда работает, но изначально скорость устанавливается равной нулю, поэтому прямоугольник не перемещается.

KeyPressed handler просто меняет скорость: на положительное значение при движении вправо и отрицательное значение при перемещении влево. Обработчик keyReleased возвращает скорость обратно к нулю.

+0

Одна из приятных (но, возможно, не очевидных) особенностей этого подхода заключается в том, что у вас есть полный программный контроль над скоростью прямоугольника; это не определяется настройками уровня ОС, такими как частота повторения клавиатуры и т. д. –

+0

Привет, Джеймс, в начале анимации все еще есть пауза, когда я поочередно нажимаю клавишу LEFT/RIGHT. Также не могли бы вы дать некоторое объяснение логике, которую вы здесь реализуете. – Angom

+0

С некоторым анализом я могу понять логику. Кроме того, я сделал небольшую модификацию внутри scene.setOnKeyReleased(), чтобы установить rectangleVelocity в 0 только тогда, когда выпущены обе кнопки LEFT/RIGHT, иначе это вызовет эффект паузы в анимации. Благодарю. – Angom

Смежные вопросы