1  import javafx.animation.KeyFrame;
  2  import javafx.animation.Timeline;
  3  import javafx.application.Application;
  4  import javafx.beans.property.DoubleProperty;
  5  import javafx.geometry.Pos;
  6  import javafx.scene.Node;
  7  import javafx.stage.Stage;
  8  import javafx.scene.Scene;
  9  import javafx.scene.control.Button;
 10  import javafx.scene.control.ScrollBar;
 11  import javafx.scene.layout.BorderPane;
 12  import javafx.scene.layout.HBox;
 13  import javafx.scene.layout.Pane;
 14  import javafx.scene.paint.Color;
 15  import javafx.scene.shape.Circle;
 16  import javafx.util.Duration;
 17  
 18  public class MultipleBounceBall extends Application {
 19    @Override // Override the start method in the Application class
 20    public void start(Stage primaryStage) {
 21      MultipleBallPane ballPane = new MultipleBallPane();
 22      ballPane.setStyle("-fx-border-color: yellow");
 23  
 24      Button btAdd = new Button("+");
 25      Button btSubtract = new Button("-");
 26      HBox hBox = new HBox(10);
 27      hBox.getChildren().addAll(btAdd, btSubtract);
 28      hBox.setAlignment(Pos.CENTER);
 29  
 30      // Add or remove a ball
 31      btAdd.setOnAction(e -> ballPane.add());
 32      btSubtract.setOnAction(e -> ballPane.subtract());
 33  
 34      // Pause and resume animation
 35      ballPane.setOnMousePressed(e -> ballPane.pause());
 36      ballPane.setOnMouseReleased(e -> ballPane.play());
 37  
 38      // Use a scroll bar to control animation speed
 39      ScrollBar sbSpeed = new ScrollBar();
 40      sbSpeed.setMax(20);
 41      sbSpeed.setValue(10);
 42      ballPane.rateProperty().bind(sbSpeed.valueProperty());
 43      
 44      BorderPane pane = new BorderPane();
 45      pane.setCenter(ballPane);
 46      pane.setTop(sbSpeed);
 47      pane.setBottom(hBox);
 48  
 49      // Create a scene and place the pane in the stage
 50      Scene scene = new Scene(pane, 250, 150);
 51      primaryStage.setTitle("MultipleBounceBall"); // Set the stage title
 52      primaryStage.setScene(scene); // Place the scene in the stage
 53      primaryStage.show(); // Display the stage
 54    }
 55  
 56    private class MultipleBallPane extends Pane {
 57      private Timeline animation;
 58  
 59      public MultipleBallPane() {
 60        // Create an animation for moving the ball
 61        animation = new Timeline(
 62          new KeyFrame(Duration.millis(50), e -> moveBall()));
 63        animation.setCycleCount(Timeline.INDEFINITE);
 64        animation.play(); // Start animation
 65      }
 66  
 67      public void add() {
 68        Color color = new Color(Math.random(), 
 69          Math.random(), Math.random(), 0.5);
 70        getChildren().add(new Ball(30, 30, 20, color)); 
 71      }
 72      
 73      public void subtract() {
 74        if (getChildren().size() > 0) {
 75          getChildren().remove(getChildren().size() - 1); 
 76        }
 77      }
 78  
 79      public void play() {
 80        animation.play();
 81      }
 82  
 83      public void pause() {
 84        animation.pause();
 85      }
 86  
 87      public void increaseSpeed() {
 88        animation.setRate(animation.getRate() + 0.1);
 89      }
 90  
 91      public void decreaseSpeed() {
 92        animation.setRate(
 93          animation.getRate() > 0 ? animation.getRate() - 0.1 : 0);
 94      }
 95  
 96      public DoubleProperty rateProperty() {
 97        return animation.rateProperty();
 98      }
 99  
100      protected void moveBall() {
101        for (Node node: this.getChildren()) {
102          Ball ball = (Ball)node;
103          // Check boundaries
104          if (ball.getCenterX() < ball.getRadius() || 
105              ball.getCenterX() > getWidth() - ball.getRadius()) {
106            ball.dx *= -1; // Change ball move direction
107          }
108          if (ball.getCenterY() < ball.getRadius() || 
109              ball.getCenterY() > getHeight() - ball.getRadius()) {
110            ball.dy *= -1; // Change ball move direction
111          }
112  
113          // Adjust ball position
114          ball.setCenterX(ball.dx + ball.getCenterX());
115          ball.setCenterY(ball.dy + ball.getCenterY());
116        }
117      }
118    }
119  
120    class Ball extends Circle {
121      private double dx = 1, dy = 1;
122  
123      Ball(double x, double y, double radius, Color color) {
124        super(x, y, radius);
125        setFill(color); // Set ball color
126      }
127    }
128    
129    /**
130     * The main method is only needed for the IDE with limited
131     * JavaFX support. Not needed for running from the command line.
132     */
133    public static void main(String[] args) {
134      launch(args);
135    }
136  }