JavaFX Animated Ball Example

The Bouncing Ball is the “Hello World” of animations in JavaFx. It’s simple to write, easy to understand and reveals the potential of JavaFx even from this primitive stage.

We will start by creating a moving ball that will set the basis for the bouncing ball that will follow.

1. Moving Ball Example

Apart from the basic set up this code has only one important line. The line where we create the Timeline. This Timeline holds two important properties; the KeyFrame and the KeyValue. What we say to the Timeline in simple English is “move the ball from where it is, to the end of the Pane in 3 seconds”. Then we also ask it -kindly- to do it twice and voilà!

MovingBall.java

package com.mkyong.javafx.animatedball;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class MovingBall extends Application{
	
    @Override
    public void start(Stage stage) {
    	Pane canvas = new Pane();
    	Scene scene = new Scene(canvas, 300, 300);
    	Circle ball = new Circle(10, Color.RED);
        ball.relocate(0, 10);
        
        canvas.getChildren().add(ball);
        
        stage.setTitle("Moving Ball");
        stage.setScene(scene);
        stage.show();
        
        Bounds bounds = canvas.getBoundsInLocal();
        Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(3), 
                new KeyValue(ball.layoutXProperty(), bounds.getMaxX()-ball.getRadius())));
        timeline.setCycleCount(2);
        timeline.play();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

Output:

javafx-animated-ball-example-1

2. Bouncing Ball

With a quick view on the code you can notice the similarities to the previous one. Our set up is pretty much the same except that the Timeline now has an EventHandler. The code inside the handle method moves the ball by dx and dy unless the ball is at the bounds of the Pane, where depending on where it is changes the dx and dy to negative step (in other words makes the ball move the other way).

BouncingBall.java

package com.mkyong.javafx.animatedball;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class BouncingBall extends Application{
	
    @Override
    public void start(Stage stage) {
    	
    	Pane canvas = new Pane();
    	Scene scene = new Scene(canvas, 300, 300, Color.ALICEBLUE);
    	Circle ball = new Circle(10, Color.CADETBLUE);
        ball.relocate(5, 5);
        
        canvas.getChildren().add(ball);
        
        stage.setTitle("Animated Ball");
        stage.setScene(scene);
        stage.show();
        
        Timeline timeline = new Timeline(new KeyFrame(Duration.millis(20), 
                new EventHandler<ActionEvent>() {

        	double dx = 7; //Step on x or velocity
        	double dy = 3; //Step on y
        	
            @Override
            public void handle(ActionEvent t) {
            	//move the ball
            	ball.setLayoutX(ball.getLayoutX() + dx);
            	ball.setLayoutY(ball.getLayoutY() + dy);

                Bounds bounds = canvas.getBoundsInLocal();
                
                //If the ball reaches the left or right border make the step negative
                if(ball.getLayoutX() <= (bounds.getMinX() + ball.getRadius()) || 
                        ball.getLayoutX() >= (bounds.getMaxX() - ball.getRadius()) ){

                	dx = -dx;

                }

                //If the ball reaches the bottom or top border make the step negative
                if((ball.getLayoutY() >= (bounds.getMaxY() - ball.getRadius())) || 
                        (ball.getLayoutY() <= (bounds.getMinY() + ball.getRadius()))){

                	dy = -dy;

                }
            }
        }));
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

Output:

javafx-animated-ball-example-2

3. Your first game

While experimenting with the Bouncing Ball example, I thought to myself what if I make it all transparent and add a MouseEvent that closes the application on click? Well… guess what… I ended up trying to catch a bouncing ball on my desktop! And that’s how I made my first game in JavaFx! Enjoy!

MyFirstGame.java

package com.mkyong.javafx.animatedball;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;

public class MyFirstGame extends Application{
	
    @Override
    public void start(Stage stage) {
    	
    	Pane canvas = new Pane();
    	Scene scene = new Scene(canvas, 300, 300, Color.TRANSPARENT);
    	Circle ball = new Circle(10, Color.DARKSLATEBLUE);
        ball.relocate(5, 5);
        
        canvas.getChildren().add(ball);
                
        stage.initStyle(StageStyle.TRANSPARENT);
        scene.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
            	Platform.exit();
                System.exit(0);
            }
        });
        stage.setTitle("Animated Ball");
        stage.setScene(scene);
        stage.show();
        
        Timeline timeline = new Timeline(new KeyFrame(Duration.millis(20), new EventHandler<ActionEvent>() {
        	double dx = 7; //Step on x or velocity
        	double dy = 3; //Step on y
        	
            @Override
            public void handle(ActionEvent t) {
            	//move the ball
            	ball.setLayoutX(ball.getLayoutX() + dx);
            	ball.setLayoutY(ball.getLayoutY() + dy);

                Bounds bounds = canvas.getBoundsInLocal();
                
                //If the ball reaches the left or right border make the step negative
                if(ball.getLayoutX() <= (bounds.getMinX() + ball.getRadius()) || 
                        ball.getLayoutX() >= (bounds.getMaxX() - ball.getRadius()) ){

                	dx = -dx;

                }

                //If the ball reaches the bottom or top border make the step negative
                if((ball.getLayoutY() >= (bounds.getMaxY() - ball.getRadius())) || 
                        (ball.getLayoutY() <= (bounds.getMinY() + ball.getRadius()))){

                	dy = -dy;

                }
                
            }
        }));
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();
    }
    
    public static void main(String[] args) {
        launch();
    }
}

Output:

javafx-animated-ball-example-3

References

  1. Java 8 in Action – Raoul-Gabriel Urma, Mario Fusco, and Alan Mycroft
  2. Animation Basics – Oracle

About the Author

author image
Marilena
Marilena Panagiotidou is a senior at University of the Aegean, in the department of Information and Communication Systems Engineering. She is passionate about programming in a wide range of languages. You can contact her at an3liram@gmail.com or through her LinkedIn.

Comments

avatar
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Aš Gražus Tamsoje Recent comment authors
newest oldest most voted
Aš Gražus Tamsoje
Guest
Aš Gražus Tamsoje

Thank you for source.
Why I cant use Group, but I must use Pane instead?