Trying to create a scrolling background effect with imageViews in javafx

Tags: ,



Im trying to create a scrolling background effect with two imageViews where one picture is on top of another picture and out of the window; then i try to scroll both down the window to create a scrolling effect by changing their y coordinates. I made a loop to do so and put a thread.sleep so it wouldnt do it too quickly. Then i reset the picutres positions and do the loop again. However, when i try to run the program, the window will never open. Taking out the loop obviously properly shows the window with the picutre.

public class TestBackground extends Application{

@Override
public void start(Stage stage) throws Exception {
    
    stage.setTitle("DRIFT STAGE");
    
    Pane game = new Pane();
    Scene gameScene = new Scene(game, 956, 740);
    ImageView background = new ImageView(getClass().getResource("bg.png").toExternalForm());
    game.getChildren().add(background);
    
    ImageView background2 = new ImageView(getClass().getResource("bg.png").toExternalForm());
    game.getChildren().add(background2);        
    background2.setY(-740);
    
    //loop to scroll background vertically
    for (int j = 0; j < 20; j++) {
        for (double i = 1.0; i < 741.0; i++) {
            background.setY(background.getY() + i);
            background2.setY(background2.getY() + i);
            
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        background.setY(0.0);
        background2.setY(-740.0);
    }
    
    stage.setScene(gameScene);
    stage.show();
    
    }
    public static void main(String[] args) { launch(args); }
}

Answer

Your loop is not the right thing to do. Use a Transition Animation on each ImageView. You want a TranslateTransition.

Something like this:

    // Animation to scroll background vertically
    TranslateTransition trans1 = new TranslateTransition(Duration.minutes(1), background);
    trans1.setFromY(0);
    trans1.setToY(740);
    trans1.setCycleCount(20);
    TranslateTransition trans2 = new TranslateTransition(Duration.minutes(1), background2);
    trans2.setFromY(-740);
    trans2.setToY(0);
    trans2.setCycleCount(20);
    ParallelTransition parTrans = new ParallelTransition(trans1, trans2);
    parTrans.play();

If your intention is to have these images as a parallax background that scrolls “forever”, set the transitions to cycle indefinitely

    trans1.setCycleCount(Animation.INDEFINITE);

and use slightly different durations for each.

If you are using the same image, don’t load it twice:

    Image bgImg = new Image(getClass().getResource("bg.png").toExternalForm());
    ImageView background = new ImageView(bgImg);
    game.getChildren().add(background);

    ImageView background2 = new ImageView(bgImg);
    game.getChildren().add(background2);

Here’s the whole start method with an added speed slider, just for fun:

@Override
public void start(Stage stage) {

    stage.setTitle("DRIFT STAGE");

    Pane game = new Pane();
    Scene gameScene = new Scene(game, 956, 740);
    Image bgImg = new Image(getClass().getResource("bg.png").toExternalForm());
    ImageView background = new ImageView(bgImg);
    ImageView background2 = new ImageView(bgImg);
    Slider speedSlider = new Slider(0, 5, 1);
    game.getChildren().addAll(background, background2, speedSlider);

    // Animation to scroll background vertically
    TranslateTransition trans1 = new TranslateTransition(Duration.seconds(10), background);
    trans1.setFromY(0);
    trans1.setToY(740);
    trans1.setInterpolator(Interpolator.LINEAR);
    trans1.setCycleCount(Animation.INDEFINITE);
    TranslateTransition trans2 = new TranslateTransition(Duration.seconds(10), background2);
    trans2.setFromY(-740);
    trans2.setToY(0);
    trans2.setCycleCount(Animation.INDEFINITE);
    trans2.setInterpolator(Interpolator.LINEAR);
    ParallelTransition parTrans = new ParallelTransition(trans1, trans2);
    parTrans.rateProperty().bind(speedSlider.valueProperty());
    parTrans.play();

    stage.setScene(gameScene);
    stage.show();
}


Source: stackoverflow