Case Study: Bouncing Ball
Tags: java, programming, learning, beginners
Published: 2024-06-24 22:37:41

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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfuh6vugf4eu2eq4ii6c.png)

Here are the major steps to write this program:

1. Define a subclass of **Pane** named **BallPane** to display a ball bouncing, as shown in code below.
2. 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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vml3l7kyoiok0mn3dcp.png)

```
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**.