JavaFX、创建一个迷宫

这是一个使用JavaFX编写的程序,展示了从左上角到右下角或从右下角到左上角的随机路径搜索动画。程序包含一个8x8的网格,每个格子是一个可点击的 Pane 对象,点击后会添加线条作为路径标记。用户可以点击 'FindPath' 按钮开始动画,'ClearPath' 按钮则清除路径。动画过程中,矩形格子会根据路径变化颜色,模拟路径搜索过程。
摘要由CSDN通过智能技术生成

package Recursive;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class Exercise18_26 extends Application {
    private ArrayList<Point2D> list = new ArrayList<>();    //存放坐标列表
    private Pane[][] panes = new Pane[8][8];    //坐标点面板
    private Button findPath = new Button("Find Path");  //按钮
    private Button clearPath = new Button("Clear Path");
    private Timeline animation; //动画
    private String orientation = "";    //开始方向(左上角-右下角)

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        GridPane gridPane = getCenterPane();
        HBox hBox = new HBox(10, findPath, clearPath);
        hBox.setAlignment(Pos.CENTER);

        findPath.setCursor(Cursor.HAND);    //按钮设置手势指针
        clearPath.setCursor(Cursor.HAND);
        findPath.setOnAction(event -> { //按钮注册动作事件
            animation = new Timeline(new KeyFrame(Duration.millis(100), event1 -> animationPath()));    //创建动画
            animation.setCycleCount(Timeline.INDEFINITE);   //无限循环次数
            animation.play();   //动画播放
        });
        clearPath.setOnAction(event -> {
            list.clear();   //清空存放坐标列表
            orientation = "";   //重置开始方向
            if (animation != null)  //停止动画
                animation.stop();
            for (Node node : gridPane.getChildren())    //坐标点面板重新添加矩形
                if (node instanceof Pane)  {    //如果结点是Pane的实例
                    ((Pane)node).getChildren().clear(); //清空面板
                    Rectangle rectangle = new Rectangle(50, 50);    //创建矩形并加入面板
                    rectangle.setStyle("-fx-stroke: lightgrey; -fx-fill: white;");  //矩形设置样式(浅灰色画线,白色填充)
                    ((Pane)node).getChildren().add(rectangle);
                }
        });

        BorderPane pane = new BorderPane(gridPane);
        pane.setTop(new StackPane(new Label("path found")));
        pane.setBottom(hBox);
        pane.getCenter().setStyle("-fx-padding: 2px 0 5px 0;");

        Scene scene = new Scene(pane);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Exercise18_26");
        primaryStage.show();
    }

    /** 返回网格面板 */
    private GridPane getCenterPane() {
        GridPane gridPane = new GridPane();
        gridPane.setGridLinesVisible(true); //设置网格线可见

        //网格面板添加坐标点面板
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                Rectangle rectangle = new Rectangle(50, 50);
                rectangle.setStyle("-fx-stroke: lightgrey; -fx-fill: white;");
                Pane pane = new Pane(rectangle);
                pane.setPrefSize(50, 50);
                pane.setCursor(Cursor.HAND);
                pane.setOnMouseClicked(event -> {   //坐标点面板注册鼠标点击事件(添加x线进入面板)
                    Line line1 = new Line(0, 0, 0, 0);
                    Line line2 = new Line(0, 0, 0, 0);
                    line1.endYProperty().bind(pane.heightProperty());
                    line1.endXProperty().bind(pane.widthProperty());
                    line2.startXProperty().bind(pane.widthProperty());
                    line2.endYProperty().bind(pane.heightProperty());
                    pane.getChildren().addAll(line1, line2);
                });
                panes[i][j] = pane;
                gridPane.add(pane, j, i);
            }
        }
        return gridPane;
    }

    /** 点在存放坐标列表中? */
    private boolean isInList(ArrayList<Point2D> list, Point2D point2D) {
        for (Point2D p : list)
            if (p.equals(point2D))
                return true;
        return false;
    }

    /** 设置随机开始方向 */
    private void setRandomOrientation() {
        if (orientation.equals(""))
            orientation = (Math.random() > 0.4) ? "rightDown" : "leftUp";
    }

    /** 动画关键帧处理器 */
    private void animationPath() {
        int x, y;   //x, y坐标
        setRandomOrientation(); //设置开始方向
        if (orientation.equals("leftUp")) { //从左上角开始
            if (list.size() == 0) { //第一个点
                list.add(new Point2D(0, 0));
                for (Node node : panes[0][0].getChildren()) //设置矩形颜色为灰色
                    if (node instanceof Rectangle) {
                        ((Rectangle)node).setFill(Color.GREY);
                        break;
                    }
            } else {    //除第一个点外的点
                Point2D lastPoint = list.get(list.size() - 1);  //获取上个移动坐标点
                if (Math.random() > 0.4) {  //垂直方向变化
                    x = (Math.random() > 0.4) ? (int)lastPoint.getX()+1 : (int)lastPoint.getX()-1;
                    y = (int)lastPoint.getY();
                } else {    //水平方向变化
                    x = (int)lastPoint.getX();
                    y = (Math.random() > 0.4) ? (int)lastPoint.getY()+1 : (int)lastPoint.getY();
                }
                if ((0 <= x && x <= 7) && (0 <= y && y <= 7))   //如果坐标在范围内
                    if (!isInList(list, new Point2D(x, y)) && panes[x][y].getChildren().size() == 1) {  //如果坐标不在坐标列表中且坐标面板未放标志
                        for (Node node : panes[x][y].getChildren())
                            if (node instanceof Rectangle) {    //设置矩形颜色
                                ((Rectangle)node).setFill(Color.GREY);
                                break;
                            }
                        list.add(new Point2D(x, y));
                        if (x == panes.length-1 && y == panes.length-1)
                            animation.stop();   //到达右下角时停止动画
                    }
            }
        } else {    //从右下角开始
            if (list.size() == 0) {
                list.add(new Point2D(panes.length-1, panes.length-1));
                for (Node node : panes[7][7].getChildren())
                    if (node instanceof Rectangle) {
                        ((Rectangle)node).setFill(Color.GREY);
                        break;
                    }
            } else {
                Point2D lastPoint = list.get(list.size() - 1);
                if (Math.random() > 0.4) {
                    x = (Math.random() > 0.4) ? (int)lastPoint.getX()+1 : (int)lastPoint.getX()-1;
                    y = (int)lastPoint.getY();
                } else {
                    x = (int)lastPoint.getX();
                    y = (Math.random() > 0.4) ? (int)lastPoint.getY()-1 : (int)lastPoint.getY();
                }
                if ((0 <= x && x <= 7) && (0 <= y && y <= 7))
                    if (!isInList(list, new Point2D(x, y)) && panes[x][y].getChildren().size() == 1) {
                        for (Node node : panes[x][y].getChildren())
                            if (node instanceof Rectangle) {
                                ((Rectangle)node).setFill(Color.GREY);
                                break;
                            }
                        list.add(new Point2D(x, y));
                        if (x == 0 && y == 0)
                            animation.stop();
                    }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值