Case Study: Bouncing Ball
Paul Ngugi
Posted on June 24, 2024
This section presents an animation that displays a ball bouncing in a pane.
The program uses Timeline to animation ball bouncing, as shown in Figure below.
Here are the major steps to write this program:
- Define a subclass of Pane named BallPane to display a ball bouncing, as shown in code below.
- Define a subclass of Application named BounceBallControl to control the bouncing ball with mouse actions, as shown in the program below. The animation pauses when the mouse is pressed and resumes when the mouse is released. Pressing the UP and DOWN arrow keys increases/decreases animation speed.
The relationship among these classes is shown in Figure below.
package application;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.DoubleProperty;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
public class BallPane extends Pane {
public final double radius = 20;
private double x = radius, y = radius;
private double dx = 1, dy = 1;
private Circle circle = new Circle(x, y, radius);
private Timeline animation;
public BallPane() {
circle.setFill(Color.GREEN); // Set ball color
getChildren().add(circle); // Place a ball into this game
// Create an animation for moving the ball
animation = new Timeline(new KeyFrame(Duration.millis(50), e -> moveBall()));
animation.setCycleCount(Timeline.INDEFINITE);
animation.play(); // Start animation
}
public void play() {
animation.play();
}
public void pause() {
animation.pause();
}
public void increaseSpeed() {
animation.setRate(animation.getRate() + 0.1);
}
public void decreaseSpeed() {
animation.setRate(animation.getRate() > 0 ? animation.getRate() - 0.1 : 0);
}
public DoubleProperty rateProperty() {
return animation.rateProperty();
}
protected void moveBall() {
// Check boundaries
if(x < radius || x > getWidth() - radius) {
dx *= -1; // Change ball move direction
}
if(y < radius || y > getHeight() - radius) {
dy *= -1; // Change ball move direction
}
// Adjust ball position
x += dx;
y += dy;
circle.setCenterX(x);
circle.setCenterX(y);
}
}
BallPane extends Pane to display a moving ball (line 10). An instance of Timeline is created to control animation (lines 22). This instance contains a KeyFrame object that invokes the moveBall() method at a fixed rate. The moveBall() method moves the ball to simulate animation. The center of the ball is at (x, y), which changes to (x + dx, y + dy) on the next move (lines 57–58). When the ball is out of the horizontal boundary, the sign of dx is changed (from positive to negative or vice versa) (lines 49–51). This causes the ball to change its horizontal movement direction. When the ball is out of the vertical boundary, the sign of dy is changed (from positive to negative or vice versa) (lines 52–54). This causes the ball to change its vertical movement direction. The pause and play methods (lines 27–33) can be used to pause and resume the animation. The increaseSpeed() and decreaseSpeed() methods (lines 35–41) can be used to increase and decrease animation speed. The rateProperty() method (lines 43–45) returns a binding property value for rate.
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
public class BounceBallControl extends Application {
@Override // Override the start method in the Application class
public void start(Stage primaryStage) {
BallPane ballPane = new BallPane(); // Create a ball pane
// Pause and resume animation
ballPane.setOnMousePressed(e -> ballPane.pause());
ballPane.setOnMouseReleased(e -> ballPane.play());
// Increase and decrease animation
ballPane.setOnKeyPressed(e -> {
if(e.getCode() == KeyCode.UP) {
ballPane.increaseSpeed();
}
else if(e.getCode() == KeyCode.DOWN) {
ballPane.decreaseSpeed();
}
});
// Create a scene and place it in the stage
Scene scene = new Scene(ballPane, 250, 150);
primaryStage.setTitle("FlagRisingAnimation"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
// Must request focus after the primary stage is displayed
ballPane.requestFocus();
}
public static void main(String[] args) {
Application.launch(args);
}
}
The BounceBallControl class is the main JavaFX class that extends Application to display the ball pane with control functions. The mouse-pressed and mouse-released handlers are implemented for the ball pane to pause the animation and resume the animation (lines 13 and 14). When the UP arrow key is pressed, the ball pane’s increaseSpeed() method is invoked to increase the ball’s movement (line 19). When the DOWN arrow key is pressed, the ball pane’s decreaseSpeed() method is invoked to reduce the ball’s movement (line 22).
Invoking ballPane.requestFocus() in line 33 sets the input focus to ballPane.
Posted on June 24, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.