- package collection;
-
- import javafx.animation.KeyFrame;
- import javafx.animation.Timeline;
- import javafx.application.Application;
- import javafx.beans.property.DoubleProperty;
- import javafx.geometry.Point2D;
- import javafx.geometry.Pos;
- import javafx.scene.Node;
- import javafx.scene.Scene;
- import javafx.scene.control.Button;
- import javafx.scene.control.ScrollBar;
- import javafx.scene.layout.BorderPane;
- import javafx.scene.layout.HBox;
- import javafx.scene.layout.Pane;
- import javafx.scene.paint.Color;
- import javafx.scene.paint.Paint;
- import javafx.scene.shape.Circle;
- import javafx.stage.Stage;
- import javafx.util.Duration;
-
- import java.security.SecureRandom;
- import java.util.ConcurrentModificationException;
-
- public class MultipleBouncePane extends Application {
- @Override
- public void start(Stage primaryStage) throws Exception {
- MultipleBallPane ballPane = new MultipleBallPane(); //创建多球面板
- ballPane.setStyle("-fx-border-color: darkseagreen;");
-
- Button suspend = new Button("Suspend"); //按钮
- Button resume = new Button("Resume");
- Button add = new Button("+");
- Button subtract = new Button("-");
- HBox hBox = new HBox(10, suspend, resume, add, subtract);
- hBox.setAlignment(Pos.CENTER);
-
- suspend.setOnAction(event -> ballPane.pause()); //按钮注册动作事件
- resume.setOnAction(event -> ballPane.play());
- add.setOnAction(event -> ballPane.add());
- subtract.setOnAction(event -> ballPane.subtract());
-
- ballPane.setOnMousePressed(event -> ballPane.pause()); //多球面板注册鼠标按下事件
- ballPane.setOnMouseReleased(event -> ballPane.play());
-
- ScrollBar speed = new ScrollBar(); //滚动条
- speed.setMax(20); //设置最大值
- speed.setValue(10); //设置值
- ballPane.rateProperty().bind(speed.valueProperty()); //多球面板速度属性绑定滚动条值属性
-
- BorderPane pane = new BorderPane(ballPane); //总面板
- pane.setTop(speed);
- pane.setBottom(hBox);
-
- Scene scene = new Scene(pane, 350, 250);
- primaryStage.setScene(scene);
- primaryStage.setTitle("MultipleBouncePane");
- primaryStage.show();
- }
-
- /** 内部类(多球面板) */
- private class MultipleBallPane extends Pane {
- private Timeline animation; //时间线动画
-
- public MultipleBallPane() {
- animation = new Timeline(new KeyFrame(Duration.millis(50), event -> moveBall()));
- animation.setCycleCount(Timeline.INDEFINITE);
- animation.play();
- }
-
- /** 添加弹球 */
- public void add() {
- Color color = new Color(Math.random(), Math.random(), Math.random(), 0.5); //创建半透明的随机颜色对象
- Ball ball = new Ball(30, 30, 2+new SecureRandom().nextInt(19), color); //创建弹球对象
- getChildren().add(ball); //多球面板添加弹球
-
- //弹球注册鼠标按下事件
- ball.setOnMousePressed(event -> {
- if (ball.isPressed()) { //如果被按下
- animation.stop();
- getChildren().remove(ball); //移除当前弹球
- animation.play();
- }
- });
- }
-
- /** 减少弹球 */
- public void subtract() {
- if (getChildren().size() > 0) { //移除最大半径的弹球
- Ball temp = (Ball)getChildren().get(0);
- for (Node node: getChildren()) {
- if (((Ball)node).getRadius() > temp.getRadius())
- temp = (Ball)node;
- }
- getChildren().remove(temp);
- }
- }
-
- /** 播放动画 */
- 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 ? 0 : animation.getRate()-0.1);
- }
-
- /** 返回动画速度属性 */
- public DoubleProperty rateProperty() {
- return animation.rateProperty();
- }
-
- /** 移动弹球 */
- protected void moveBall() {
- try {
- for (Node node : this.getChildren()) { //遍历弹球列表
- Ball ball = (Ball)node;
-
- //到达边界时改变方向
- if (ball.getCenterX() < ball.getRadius() || ball.getCenterX() > getWidth()-ball.getRadius())
- ball.dx *= -1;
- if (ball.getCenterY() < ball.getRadius() || ball.getCenterY() > getHeight()-ball.getRadius())
- ball.dy *= -1;
-
- //设置新坐标
- ball.setCenterX(ball.dx + ball.getCenterX());
- ball.setCenterY(ball.dy + ball.getCenterY());
-
- //合并弹球(在边界时弹球半径的突然增大会呈水平或垂直方向(拉伸场景可解决))
- for (Node node1: this.getChildren()) { //再次遍历列表
- Ball ball1 = (Ball)node1;
-
- //如果俩球不相等且相交
- if (!ball1.equals(ball) && (new Point2D(ball.getCenterX(), ball.getCenterY()).distance(ball1.getCenterX(),
- ball1.getCenterY()) <= ball.getRadius()+ball1.getRadius())) {
- int index1 = getChildren().indexOf(ball); //获取弹球下标
- int index2 = getChildren().indexOf(ball1);
-
- //移除后面的球
- if (index1 < index2) {
- ball.setRadius(ball.getRadius() + ball1.getRadius());
- getChildren().remove(ball1);
- } else {
- ball1.setRadius(ball1.getRadius() + ball.getRadius());
- getChildren().remove(ball);
- }
- }
- }
- }
- } catch (ConcurrentModificationException ex) { //捕获并发修改异常
- }
- }
-
- }
-
- /** 内部类(弹球类) */
- class Ball extends Circle {
- private double dx = 1, dy = 1;
-
- public Ball(double centerX, double centerY, double radius, Paint fill) {
- super(centerX, centerY, radius, fill);
- }
- }
- }