0

In this program, I am trying to make rect turn red when x== 600 in the for-loop. What basically happens is that the for-loop runs faster than the animation on the screen. The rectangle ends up turning red before it actually hits that certain point within the JavaFX screen.

What I would like it to do it that when it hits point x,y:(600,500), make the blue rectangle turn red.

import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 *
 * @author Owner
 */
public class TestPoint extends Application {

    @Override
    public void start(Stage primaryStage) {

        Pane root = new Pane();
        Scene scene = new Scene(root, 1000, 1000);
        Rectangle rect = new Rectangle();
        Rectangle rectTwo = new Rectangle();

        //Obstacle that other square must hit
        rectTwo.setWidth(100);
        rectTwo.setHeight(100);
        rectTwo.setX(500);
        rectTwo.setY(500);
        rectTwo.setFill(Color.PINK);

        //for loop that causes the animation to properly move
        for (int x = 800; x >= 0; x--) {
            rect.setWidth(100);
            rect.setHeight(100);
            rect.setX(800);
            rect.setY(500);
            rect.setFill(Color.BLUE);
            Timeline timeline = new Timeline();
            timeline.setCycleCount(1);
            timeline.setAutoReverse(true);
            final KeyValue kv = new KeyValue(rect.xProperty(), x);
            final KeyFrame kf = new KeyFrame(Duration.seconds(8), kv);
            timeline.getKeyFrames().add(kf);
            timeline.play();
            //if it hits the point of rectTwo, change to Color.RED
            System.out.println(x);
            if (x == 600) {
                rect.setFill(Color.RED);
                break;//end 
            }
        }

        root.getChildren().addAll(rect, rectTwo);
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

1 Answers1

3

You misunderstood, how Timeline works. Your code creates 201 Timeline animations running in parallel. The loop is done before the window is shown. Any updates are automatically triggered by JavaFX later.

Specifying the initial state and the target state via KeyFrames is sufficient. KeyFrames allow you to specify a handler to be executed at a specific time; this can be used to change the color. Alternatively the onFinished handler could be used for coloring the Rectangle.

rect.setWidth(100);
rect.setHeight(100);
rect.setY(500);
rect.setFill(Color.BLUE);

Timeline timeline = new Timeline(
        new KeyFrame(Duration.ZERO, new KeyValue(rect.xProperty(), 800)),
        new KeyFrame(Duration.seconds(8),
                evt -> rect.setFill(Color.RED),
                new KeyValue(rect.xProperty(), 600)));
timeline.play();
fabian
  • 80,457
  • 12
  • 86
  • 114
  • Can I use a collision detector too, like BooleanBinding or is this method better? – Patryk Kownacki Feb 08 '19 at 14:58
  • For collision detection you could trigger stepwise updates using a single `KeyFrame` with an event handler with a small duration to do an "update loop" which allows you to do the collision checks after the updates are done, you could use a seperate `AnimationTimer` or you could register a listener to the `x` property of the rect...The listener approach is the most likely to repeat checks, if you create more complex animations. – fabian Feb 08 '19 at 15:56
  • How would I go on about with creating the listener to the x property of the rectangle? Any tutorials I can watch? – Patryk Kownacki Feb 09 '19 at 00:22
  • Just check out the `addListener` methods: [`ObservableValue`](https://openjfx.io/javadoc/11/javafx.base/javafx/beans/value/ObservableValue.html#addListener%28javafx.beans.value.ChangeListener%29) and [`Observable`](https://openjfx.io/javadoc/11/javafx.base/javafx/beans/Observable.html#addListener%28javafx.beans.InvalidationListener%29). Shouldn't be too hard to implement one of those interfaces even without doing a tutorial. Example: `rect.xProperty().addListener(o -> { ... });` – fabian Feb 09 '19 at 01:19