0

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); }
}
johndo19
  • 13
  • 3
  • See https://stackoverflow.com/questions/64555374/how-do-you-refresh-javafx-scene-from-inside-an-button-action/64555707#64555707 – James_D Nov 20 '20 at 20:32
  • so i need to create a timeline? – johndo19 Nov 20 '20 at 20:39
  • That’s the easiest way – James_D Nov 20 '20 at 20:44
  • @James_D so do i put my loop inside a public void handle(ActionEvent event) method like in this answer? https://stackoverflow.com/questions/49881109/how-to-properly-execute-thread-sleep-in-javafx?noredirect=1&lq=1 – johndo19 Nov 20 '20 at 20:49
  • You should solve it the same way as either the one I linked, or the one you linked. Neither one puts a loop in the event handler. The timeline replaces the loop. – James_D Nov 20 '20 at 21:07
  • @James_D how would that work if i need to have two for loops so i can reset the pictures position? – johndo19 Nov 20 '20 at 21:21
  • im also going to make it run infinitely by changing the first for loop into a while loop thats always true, will timeline work with that? – johndo19 Nov 20 '20 at 21:27
  • Again, you replace the loop with a timeline. Read the other questions. – James_D Nov 20 '20 at 21:36

1 Answers1

0

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();
}
swpalmer
  • 3,890
  • 2
  • 23
  • 31
  • this does seem to be what im looking for except it seems to only move the first background down but not the second one leaving a white space before resetting the transition see here: https://imgur.com/a/Phm81jD – johndo19 Nov 21 '20 at 03:08
  • Get rid of background2.setY(-740); you don't need it anymore – swpalmer Nov 21 '20 at 03:44
  • Thanks this is very helpful! Is there a way for it to scroll more smoothly since there's a tiny delay from when it scrolls again. – johndo19 Nov 21 '20 at 04:20