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à!
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:
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).
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:
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!
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:
what should I do to make multiple balls instead of the single ball?
Thank you for source.
Why I cant use Group, but I must use Pane instead?
HI
new EventHandler<ActionEvent>() {
I have problem with EventHandler< a compiler not found “<”
thanks
it is < character for but there was an issue in display I guess
.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler() {
@Override
public void handle(MouseEvent event) {
System.out.println(“do somthing”);
}
});
Thanks Bro
Lookslike < character had problem it gives strange character but when I replaced it worked. Thanks
hi, does anyone know how to make the circle differ from bigger to smaller during the runtime and how to make it change speed during the process