user11577572
user11577572

Reputation:

How to make the timelines stop stucking together?

I have a javafx project which there is a circle and four buttons(left,right,up,down). When you press a button the circle will start move on button s direction. If you press another button the circle has to change direction. If you press the circle it will turn red and the timeline will stop. The problem is every time you press the button for a second time it will update the timeline but it will make another timeline and the circle will go carzy.

I've tried to stop the timeline every time someone press a button but didn't work.

Timeline animation;
btnL.setOnAction(e -> {
 if(check == false){
  animation = new Timeline(new KeyFrame(Duration.millis(50), f->  moveBall('l')));
  animation.setCycleCount(Timeline.INDEFINITE);
  animation.play();
  check = true;
 }
});
btnR.setOnAction(e -> {
 if(check == false){
  animation = new Timeline(new KeyFrame(Duration.millis(50), f-> moveBall('r')));
  animation.setCycleCount(Timeline.INDEFINITE);
  animation.play();
  check = true;
 }
});
btnU.setOnAction(e -> {
 if(check == false){
  animation = new Timeline(new KeyFrame(Duration.millis(50), f-> 
moveBall('u')));
  animation.setCycleCount(Timeline.INDEFINITE);
  animation.play();
  check = true;
 }
});
btnD.setOnAction(e -> {
 if(check == false){
  animation = new Timeline(new KeyFrame(Duration.millis(50), f-> moveBall('d')));
  animation.setCycleCount(Timeline.INDEFINITE);
  animation.play();
  check = true;
 }
});
circle.setOnMouseClicked(e -> {
 circle.setFill(Color.RED);
 animation.stop();
 check = false;
});

In the end I made a boolean check to checking if someone has press the button and the ball is moving any other button will do nothing. But I believe there is anoter solution more correct.

Upvotes: 0

Views: 83

Answers (1)

fabian
fabian

Reputation: 82461

Stopping the timeline before creating a new one should work:

btnL.setOnAction(e -> {
    if(!check) {
        if (animation != null) {
            animation.stop(); // stop old animation
        }
        animation = new Timeline(new KeyFrame(Duration.millis(50), f->  moveBall('l')));
        animation.setCycleCount(Timeline.INDEFINITE);
        animation.play();
        check = true;
    }
});

Since the only thing you're changing is the char you pass to moveBall, you could simply store this value in a field and use only a single Timeline:

private char direction = 0;
private final Timeline animation = new Timeline(new KeyFrame(Duration.millis(50), f-> moveBall(direction)));

{
    animation.setCycleCount(Timeline.INDEFINITE);
}

private void setDirection(char direction) {
    if (!check) {
        this.direction = direction;
        animation.playFromStart();
        check = true;
    }
}
btnL.setOnAction(e -> setDirection('l'));
btnR.setOnAction(e -> setDirection('r'));
...

Note: I'm assuming check is set to false somewhere in code that you have not shown. Otherwise only a click on the circle allows other button presses for other button press from having any effect after the initial one. If not, simply remove the if and the assignment and keep only the rest of the body of the if.

Upvotes: 4

Related Questions