Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Wednesday, December 30, 2015

A Looping Background for a Game Using JavaFX and Scene Builder

Games like Super Mario Bros or Flappy Birds scroll a background from right to left to give the appearance of motion.  This example instantiates a single long image twice and scrolls both.  While the first image scrolls off, the second image begins to appear.  The second image scrolls off and the first image -- now reset -- repeats the loop.


All of the code in this post can be found on GitHub at bekwam/examples-javafx-repos1.

This video demonstrates the technique.  A blue sky appears over a green ground.  Several white clouds come into view and are scrolled off the left.  Because the image is large and the white clouds were created individually, it isn't apparent right away that the background is in a loop.  Focusing on the game -- not just the scrolling -- will make the background even less relevant.



THIS IS NOW SANDBOXED

If you would like to see the animation for yourself, here is the JNLP: https://www.bekwam.net/background-sandbox/background.jnlp.

Originally, I had to make this an all-permissions.  Read more about the sandboxing here.

Alternatively, you can download the code and run it from your IDE.

Scene Builder

To start the demo off, let's look at Scene Builder.  I use two ImageViews containing the same 2000px image for the background.  The ImageViews are added to a Pane.  The first ImageView is partially displayed in the following screenshot (half of it is cropped by the Pane container).  The second ImageView is completely cropped.  It has an X of 2000, so it's not on the screen at startup.

Background App Scene Builder Definition
The Pane containing the ImageViews is combined with a control Button in a StackPane.

Scene Builder is key in this post because it lets me quickly preview the screen by simply pressing Control-P.  I can also tweak the resizing behavior and test the compression and spacing and different sizes.

Main Program

The main is a trivial display of a Stage and Scene.  The Scene Builder-generated FXML file is loaded using an FXMLLoader.  I start the animation by executing a method in the Controller.  The start action is initiated from the Stage's onShown.

Controller

The algorithm that I'm using for the app is to slide both ImageViews from right to left.  The first ImageView, background1, is initially shown.  Because background1 is wider than the screen, it is shown for a while.  Once the 2000 pixels of background1 start rolling off the screen, the second ImageView, background2, is shown.  It has been moving during background1's animation.  However, because it was offset with an X=2000 in Scene Builder, it doesn't come into view until background1 starts leaving the view.

This simultaneous motion -- both ImageViews moving but with an offset -- is perfect for a JavaFX ParallelTransition.  ParallelTransition can move two similarly-sized animations in lockstep.  In this case, I have identical TranslateTransitions for each ImageView.  Again, the difference in in the initial offset.

Here is the code for the ParallelTransition in the Controller @FXML initialize() method.  Note that the ParallelTransition's status drives the control Button at the end of the method.

private int BACKGROUND_WIDTH = 2000;
private ParallelTransition parallelTransition;
 
@FXML
public void initialize() {
  
 TranslateTransition translateTransition =
        new TranslateTransition(Duration.millis(10000), background1);
 translateTransition.setFromX(0);
 translateTransition.setToX(-1 * BACKGROUND_WIDTH);
 translateTransition.setInterpolator(Interpolator.LINEAR);
 
 TranslateTransition translateTransition2 =
        new TranslateTransition(Duration.millis(10000), background2);
 translateTransition2.setFromX(0);
 translateTransition2.setToX(-1 * BACKGROUND_WIDTH);
 translateTransition2.setInterpolator(Interpolator.LINEAR);

 parallelTransition = 
  new ParallelTransition( translateTransition, translateTransition2 );
 parallelTransition.setCycleCount(Animation.INDEFINITE);

 //
 // Sets the label of the Button based on the animation state
 //
 parallelTransition.statusProperty().addListener((obs, oldValue, newValue) -> {
  if( newValue == Animation.Status.RUNNING ) {
   btnControl.setText( "||" );
  } else {
   btnControl.setText( ">" );
  }
 });
}

The remainder of the Controller are the actions registered to the Button.  Recall that startAnimation() is also called from the Stage's onShown event.

public void startAmination() {
 
 parallelTransition.play();
}

public void pauseAnimation() {
 parallelTransition.pause();
}

@FXML
public void controlPressed() {
 if( parallelTransition.getStatus() == Animation.Status.RUNNING ) {
  pauseAnimation();
 } else {
  startAmination();
 }
}

This post highlights the power and simplicity of the Animations and Transitions of JavaFX.  With a single TranslateTransition, I can send an ImageView across the screen.  A pair of TranslateTransitions can be combined in a ParallelTransition to move two ImageViews in sync.  The composable transitions is a highly scalable design that will allow for layering more complex backgrounds.


8 comments:

  1. Very useful post. This is my first time i visit here. I found so many interesting stuff in your blog especially its discussion. Really its great article. Keep it up. gamerbolt.com

    ReplyDelete
  2. There is so much in this article that I would never have thought of on my own. Your content gives readers things to think about in an interesting way. Thank you for your clear information. generateur v bucks

    ReplyDelete
  3. I wanted to thank you for this excellent read!! I definitely loved every little bit of it. I have you bookmarked your site to check out the new stuff you post. 토토사이트

    ReplyDelete
  4. Very good written article. It will be supportive to anyone who utilizes it, including me. Keep doing what you are doing – can’r wait to read more posts. visit site

    ReplyDelete
  5. I found your this post while searching for information about blog-related research ... It's a good post .. keep posting and updating information. SEO canada

    ReplyDelete
  6. Nice post! This is a very nice blog that I will definitively come back to more times this year! Thanks for informative post. kingboost.net

    ReplyDelete
  7. Thanks for posting this info. I just want to let you know that I just check out your site and I find it very interesting and informative. I can't wait to read lots of your posts. bet.pt

    ReplyDelete
  8. If you are looking for the best boosting services then search for Epiccarry

    ReplyDelete