JavaFX bouncing ball example

In this example, let’s see how to make a ball which bounces back when it reaches the borders of the application:

package com.example.testjavafx;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
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 BallBounce extends Application {
    private static final int WIDTH = 800;
    private static final int HEIGHT = 600;
    private static final int RADIUS = 30;
    private static final int SPEED = 5;

    private double dx = SPEED;
    private double dy = SPEED;

    public void start(Stage primaryStage) {

        Circle ball = new Circle(RADIUS, Color.BLUE);

        Pane root = new Pane(ball);
        Scene scene = new Scene(root, WIDTH, HEIGHT);


        Timeline timeline = new Timeline(
                new KeyFrame(Duration.millis(20), e -> {

    private void calculatePosition(Circle ball) {
        ball.setLayoutX(ball.getLayoutX() + dx);
        ball.setLayoutY(ball.getLayoutY() + dy);

        if (ball.getLayoutX() <= RADIUS || ball.getLayoutX() >= WIDTH - RADIUS) {
            dx = -dx;
        if (ball.getLayoutY() <= RADIUS || ball.getLayoutY() >= HEIGHT - RADIUS) {
            dy = -dy;

    public static void main(String[] args) {

A red Circle object is created with a radius of 30 pixels. The Circle is then added to a Pane, which is set as the root node of a Scene with a width of 800 pixels and a height of 600 pixels. The Timeline animation updates the position of the ball on the Pane based on the current coordinates dx and dy values, which are initially set to 5 pixels per animation frame. If the ball hits the edge of the Scene, the dx or dy value is reversed to simulate a bounce.

Leave a Comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.