javaanimationjavafxtimeline

JavaFX animations playing simultaneously in timeline


I'm pretty new to JavaFX. I am trying to make this timeline where each keyframe happens after the previous one has finished. So far, each of the steps happen one after the other like I want it to. However, the rotateBack keyframe starts rotating my object as soon as I play the animation. Any tips on how to make rotateBack only play right after moveToRight? Also, I would like for rotateBack to finish its rotation before moveToTop plays. Thanks.

Pane selectedPane = select_pane.getValue();
                    
    double rootWidth = root_pane.getWidth();
    double rootHeight = root_pane.getHeight();
    double sixthWidth = rootWidth / 6;

    KeyValue moveTopLeftX = new KeyValue(selectedPane.layoutXProperty(), 0);
    KeyValue moveDownY = new KeyValue(selectedPane.layoutYProperty(), root_pane.getHeight()                   -    selectedPane.getHeight());

    KeyValue moveRightX = new KeyValue(selectedPane.layoutXProperty(), sixthWidth);
    KeyValue rotate180 = new KeyValue(selectedPane.rotateProperty(), 180);
    KeyValue moveToTopY = new KeyValue(selectedPane.layoutYProperty(), 0);

    KeyFrame startFrame = new KeyFrame(Duration.seconds(3), moveTopLeftX, moveToTopY);
    KeyFrame moveToRight = new KeyFrame(Duration.seconds(2), moveRightX);
    KeyFrame rotateBack = new KeyFrame(Duration.seconds(3), rotate180);
    KeyFrame moveToBottom = new KeyFrame(Duration.seconds(6), moveDownY);
    KeyFrame moveToTop = new KeyFrame(Duration.seconds(6), moveToTopY);

    Timeline timeline = new Timeline(startFrame, moveToBottom, moveToRight, rotateBack, moveToTop);

    timeline.play();

What I've tried so far is shown in the code above. Any tips very much appreciated.


Solution

  • To play a keyframe only after one is finished you can create different Timeline and in the timeline.setOnFinished() function you can play the next one.
    For your example it would look like this :

    Pane selectedPane = select_pane.getValue();
                    
    double rootWidth = root_pane.getWidth();
    double rootHeight = root_pane.getHeight();
    double sixthWidth = rootWidth / 6;
    
    KeyValue moveTopLeftX = new KeyValue(selectedPane.layoutXProperty(), 0);
    KeyValue moveDownY = new KeyValue(selectedPane.layoutYProperty(), root_pane.getHeight()                   -    selectedPane.getHeight());
    
    KeyValue moveRightX = new KeyValue(selectedPane.layoutXProperty(), sixthWidth);
    KeyValue rotate180 = new KeyValue(selectedPane.rotateProperty(), 180);
    KeyValue moveToTopY = new KeyValue(selectedPane.layoutYProperty(), 0);
    
    KeyFrame startFrame = new KeyFrame(Duration.seconds(3), moveTopLeftX, moveToTopY);
    KeyFrame moveToRight = new KeyFrame(Duration.seconds(2), moveRightX);
    KeyFrame rotateBack = new KeyFrame(Duration.seconds(3), rotate180);
    KeyFrame moveToBottom = new KeyFrame(Duration.seconds(6), moveDownY);
    KeyFrame moveToTop = new KeyFrame(Duration.seconds(6), moveToTopY);
    
    Timeline timelineStart = new Timeline(startFrame, moveToBottom, moveToRight);
    
    Timeline timelineRotateBack = new Timeline(rotateBack);
    
    Timeline timelineMoveToTop = new Timeline(moveToTop);
    
    timelineStart.setOnFinished(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    timelineRotateBack.play();
                }
            });
    
    timelineRotateBack.setOnFinished(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    timelineMoveToTop.play();
                }
            });
    
    timelineStart.play();
    

    Here it will play all these KeyFrames (startFrame, moveToBottom, moveToRight) first and when all animations are finished it will play rotateBack KeyFrame and when this one is finished it will play moveToTop