基于Java的迷宫游戏

Tommorow

发布日期: 2018-10-29 10:56:10 浏览量: 1622
评分:
star star star star star star star star_border star_border star_border
*转载请注明来自write-bug.com

一 需求分析

系统需实现以下功能:

  • 迷宫的随机生成

    • 能随机生成单元格像素宽度为10,迷宫行列长度为40*40的迷宫
  • 寻找路径

    • 能寻找从起点到终点的路径
  • 遍历迷宫

    • 能走遍迷宫内的所有点获得迷宫地图
  • 清空迷宫

    • 能清除已经生成的迷宫,以便再次生成不同的随机迷宫
  • 动态实现走迷宫的过程

    • 即运用动画效果,用一个小球模拟电脑鼠在计算机上展示出走迷宫的过程

二 程序设计

2.1 总体设计

系统总体结构如下图:

2.2 关键算法设计

2.2.1 生成迷宫的算法

算法思路

指定40*40大小的迷宫,从迷宫的(0,0)点开始访问,访问四个方向中的随机一个点(每访问到一个可访问的点,就去掉该点的那个方向的墙),被访问点继续以这种方识向下进行访问。对每个被访问的点都被标识为已访问,当一个点对某个方向进行访问时我们首先会判断被访问点是否已被访问,或者触到边界.如果该点四个方向皆已访问或已无法访问,就退回上一个点,上一个点继续这个过程。

算法实现

主要是利用栈,第一次,先把第一个点压进栈里,每访问到一个点,就把该点压进栈里,再对栈顶的点进行四个方向的随机访问,访问到新点,又把新点压进去,一旦这个点四个方向都无法访问了,就让该点退栈,再对栈顶的点的四个方向进行访问,以此类推,直到栈里的点都全部退出了,迷宫成功生成了。

算法流程图如下:

2.2.2 寻找路径的算法

算法思路

从迷宫的第一个单元格开始,随机访问它相邻的四个单元格的其中一个格子,判断他们之间是否有通路,有通路则继续以这种方式往下访问,若无通路或者四个单元格都已经访问,则返回上一个单元格继续访问,直至访问到迷宫中的最后一个单元格。

算法实现

主要也是利用栈。将第一个单元格的行列坐标压入栈里,随机访问一个它相邻的四个单元格的一个,将其标记为已访问并将其坐标压入栈里,判断该单元格的坐标是否是终点坐标,若是,则停止访问,若不是,则判断该单元格与上一个单元格之间是否有通路,若有,则继续往下访问,若没有,则将该单元格的坐标从栈顶删除,并返回上一个单元格重新访问,直至访问至终点坐标,这样栈里面就存储了从起点到终点的可行路径。在访问时,利用右手法则进行访问。

算法流程图如下:

2.2.3 遍历迷宫的算法

算法思路

随机访问迷宫里的一个单元格,并标记为已访问,然后随机访问该单元格相邻的四个单元格,并标记为已访问。判断已访问的单元格数是否等于全部单元格的个数,若两者相等,则停止访问,遍历完成,若不相等,则继续往下访问。若正访问的单元格相邻四个单元格均已访问过,则随机从所有单元格随机再取出一个单元格继续访问,以此类推,直到所有单元格都被访问过为止。

算法实现

主要利用栈。从所有单元格里随机取出一个单元格,标记为已访问,将其坐标压入栈里,接着随机访问一个相邻的单元格,并标记为已访问,将其坐标压入栈里。此时判断栈的长度是否等于等于0,若相等,则停止访问,遍历完成,若不相等,继续往下访问。若正访问的单元格相邻四个单元格均已访问过,则删除栈顶单元格的坐标,然后随机从所有单元格随机再取出一个单元格继续访问,以此类推,直到所有单元格都被访问过为止。采用左手法则进行遍历。

算法流程图如下:

三 程序实现

3.1 关键类与方法

类之间的协作关系如下图所示:

3.1.1 UI类

主要用于显示界面和完成各个功能。

包含的方法如下:

  • Start(StageprimaryStage):重写start面板
  • creatXY():绘制X,Y坐标
  • creatButton():控制按钮的生成
  • paintMaze():绘制出迷宫
  • paintCell(Stringstring):绘制单元格的墙壁
  • creatLine(intx1,y1,x2,y2):绘制单元格的一面墙
  • paintball():绘制小球
  • Mazefile():随机生成迷宫的数据文件,将其写入磁盘
  • PaintMoveBall1(inti,int j,int m,int n):绘制寻找路径时小球的行走路线
  • PaintMoveBall2(inti,int j,int m,int n):绘制遍历迷宫时小球的行走路线
  • InputMaze():将迷宫地图导入栈中
  • moveBall():控制小球移动
  • travelMaze():遍历迷宫时控制动画的函数
  • deleteMzae():清除迷宫
  • exit():用于退出程序
  • findWay():用于寻找路径的函数
  • travel():用于遍历迷宫的函数
  1. package io.github.xieyezi;
  2. import java.io.File;
  3. import java.io.FileNotFoundException;
  4. import java.io.PrintWriter;
  5. import java.util.ArrayList;
  6. import java.util.Random;
  7. import java.util.Scanner;
  8. import javafx.animation.KeyFrame;
  9. import javafx.animation.Timeline;
  10. import javafx.application.Application;
  11. import javafx.geometry.Insets;
  12. import javafx.geometry.Pos;
  13. import javafx.scene.Scene;
  14. import javafx.scene.control.Button;
  15. import javafx.scene.layout.BorderPane;
  16. import javafx.scene.layout.Pane;
  17. import javafx.scene.layout.VBox;
  18. import javafx.scene.paint.Color;
  19. import javafx.scene.shape.Circle;
  20. import javafx.scene.shape.Line;
  21. import javafx.scene.text.Text;
  22. import javafx.stage.Stage;
  23. import javafx.util.Duration;
  24. public class UI extends Application {
  25. private int countLine; // 绘制迷宫时控制跨行
  26. private int currentX; // 绘制迷宫时定位X坐标
  27. private int currentY; // 绘制迷宫时定位Y坐标
  28. private int ballCol = 0;// 小球当前所在列
  29. private int ballRaw = 0;// 小球当前所在行
  30. private final int LENGTH = 10; // 迷宫一个单元格一面墙的长度
  31. private Timeline animation; // 显示小球路径的动画
  32. Pane pane = new Pane();// 用来装迷宫的面板
  33. BorderPane borderpane1 = new BorderPane(); // 用来装迷宫的pane,用于清除迷宫
  34. BorderPane borderpane = new BorderPane(); // 主面板
  35. Circle ball = new Circle(55, 55, 5);// 模拟电脑鼠运动的小球
  36. Button bt1 = new Button("生成迷宫");
  37. Button bt2 = new Button("寻找路径");
  38. Button bt3 = new Button("遍历迷宫");
  39. Button bt4 = new Button("最短路径");
  40. Button bt5 = new Button("清空迷宫");
  41. Button bt6 = new Button("退出游戏");
  42. VBox vbox = new VBox(bt1, bt2, bt3, bt4, bt5, bt6);
  43. cell[][] cell = new cell[40][40];// 存储小球在迷宫的行列位置
  44. myStack stack = new myStack();// 存储运动位置的栈
  45. // 主函数
  46. public static void main(String[] args) {
  47. Application.launch(args);
  48. }
  49. // 重写start显示面板
  50. @Override
  51. public void start(Stage primaryStage) throws Exception {
  52. creatXY(); // 绘制坐标轴
  53. createButton(); // 生成控制按钮
  54. vbox.setSpacing(20);
  55. vbox.setAlignment(Pos.CENTER);
  56. borderpane.setRight(vbox);
  57. //borderpane1.setBottom(getHBOox());
  58. borderpane1.setCenter(pane);
  59. borderpane.setCenter(borderpane1);
  60. borderpane.setPadding(new Insets(0, 30, 12, 0));
  61. Scene scene = new Scene(borderpane, 600, 500);
  62. primaryStage.setTitle("MouseMaze");
  63. primaryStage.setScene(scene);
  64. primaryStage.show();
  65. }
  66. // 绘制坐标轴函数
  67. private void creatXY() {
  68. Line l1 = new Line(50, 50, 450, 50);// X轴
  69. l1.setStrokeWidth(2);
  70. Line l2 = new Line(50, 50, 50, 450);// Y轴
  71. l2.setStrokeWidth(2);
  72. Text t1 = new Text(40, 40, "(50,50)");
  73. Text t2 = new Text(440, 40, "X (450,50)");
  74. Text t3 = new Text(35, 450, "Y");
  75. Text t4 = new Text(35, 465, "(50,450)");
  76. borderpane.getChildren().addAll(l1, l2, t1, t2, t3, t4);
  77. }
  78. // 控制按钮生成
  79. private void createButton() {
  80. bt1.setMinSize(80, 40);// 定义按钮的大小
  81. bt1.setStyle("-fx-border-color: blue");// 定义按钮边框的颜色
  82. bt2.setMinSize(80, 40);
  83. bt2.setStyle("-fx-border-color: blue");
  84. bt3.setMinSize(80, 40);
  85. bt3.setStyle("-fx-border-color: blue");
  86. bt4.setMinSize(80, 40);
  87. bt4.setStyle("-fx-border-color: blue");
  88. bt5.setMinSize(80, 40);
  89. bt5.setStyle("-fx-border-color: blue");
  90. bt6.setMinSize(80, 40);
  91. bt6.setStyle("-fx-border-color: blue");
  92. // 按钮的功能的生成
  93. bt1.setOnAction(e -> paintMaze());
  94. bt2.setOnAction(e -> {
  95. animation = new Timeline(new KeyFrame(Duration.millis(5), e1 -> moveBall()));
  96. animation.setCycleCount(Timeline.INDEFINITE);
  97. animation.play();
  98. });
  99. bt3.setOnAction(e -> travelMzae());
  100. bt4.setOnAction(e -> samllWay());
  101. bt5.setOnAction(e -> deleteMaze());
  102. bt6.setOnAction(e -> exit());
  103. }
  104. // 主面板的底部界面
  105. // private HBox getHBOox() {
  106. // HBox hbox = new HBox();
  107. // // 以下四个文本域分别表示为起点的x,y坐标和终点的x,y坐标
  108. // TextField startX = new TextField();
  109. // TextField startY = new TextField();
  110. // TextField endX = new TextField();
  111. // TextField endY = new TextField();
  112. // startX.setPrefSize(40, 10);
  113. // startY.setPrefSize(40, 10);
  114. // endX.setPrefSize(40, 10);
  115. // endY.setPrefSize(40, 0);
  116. // Label l1 = new Label("起点坐标:");
  117. // Label l2 = new Label("终点坐标:");
  118. // l1.setTextFill(Color.RED);
  119. // l2.setTextFill(Color.RED);
  120. // l1.setFont(Font.font("Times New Roman", FontWeight.BOLD, 18));
  121. // l2.setFont(Font.font("Times New Roman", FontWeight.BOLD, 18));
  122. // hbox.getChildren().addAll(l1, startX, startY, l2, endX, endY);
  123. // hbox.setAlignment(Pos.TOP_CENTER);
  124. // hbox.setSpacing(5);
  125. // return hbox;
  126. // }
  127. // 绘制迷宫
  128. private void paintMaze() {
  129. try {
  130. Mazefile(); // 随机生成迷宫数据文件并将其存入磁盘
  131. } catch (Exception e1) {
  132. e1.printStackTrace();
  133. }
  134. paintBall(); // 生成模拟电脑鼠的小球
  135. countLine = 0; // 控制换行
  136. currentX = 50; // 迷宫的起点坐标的x坐标
  137. currentY = 50; // 迷宫的起点坐标的y坐标
  138. File file = new File("Maze.txt");
  139. Scanner input = null;
  140. try {
  141. input = new Scanner(file);
  142. while (input.hasNext()) {
  143. String str = input.next();
  144. paintCell(str); // 绘制墙壁
  145. }
  146. } catch (FileNotFoundException e) {
  147. e.printStackTrace();
  148. } finally {
  149. input.close();
  150. }
  151. inputMaze();// 获取迷宫数据存入Cell
  152. }
  153. // 绘制墙壁
  154. private void paintCell(String str) {
  155. if (str.charAt(0) == '0')
  156. createLine(currentX, currentY, currentX + LENGTH, currentY);// 绘制单元格上边的墙
  157. if (str.charAt(1) == '0')
  158. createLine(currentX + LENGTH, currentY, currentX + LENGTH, currentY + LENGTH);// 绘制单元格右边的墙
  159. if (str.charAt(2) == '0')
  160. createLine(currentX, currentY + LENGTH, currentX + LENGTH, currentY + LENGTH);// 绘制单元格下边的墙
  161. if (str.charAt(3) == '0')
  162. createLine(currentX, currentY, currentX, currentY + LENGTH); // 绘制单元格左边的墙
  163. currentX += LENGTH; // 绘制下一个单元格
  164. countLine++;
  165. if (countLine % 40 == 0)// 控制绘制下一行
  166. {
  167. currentX = 50;
  168. currentY += LENGTH;
  169. }
  170. }
  171. // 绘制单元格的一面墙壁
  172. private void createLine(int x1, int y1, int x2, int y2) {
  173. Line line = new Line(x1, y1, x2, y2);
  174. line.setStrokeWidth(2);
  175. line.setFill(Color.BLACK);
  176. pane.getChildren().add(line);
  177. }
  178. // 绘制小球
  179. private void paintBall() {
  180. ball.setCenterX(55);
  181. ball.setCenterY(55);
  182. ball.setRadius(5);
  183. ball.setStroke(null);
  184. ball.setFill(Color.RED);
  185. pane.getChildren().add(ball);
  186. }
  187. // 随机生成迷宫数据文件函数 ,“0”表示有墙,“1”表示无墙
  188. public void Mazefile() throws Exception {
  189. // 生成迷宫数据 存储到pointList链表里面
  190. File file = new File("Maze.txt");
  191. PrintWriter output = new PrintWriter(file);
  192. Maze maze = new Maze();
  193. ArrayList<mazePoint> pointList = new ArrayList<mazePoint>();
  194. pointList = maze.getMaze();
  195. int i = 0;
  196. // 定义随机数的一个对象
  197. Random random = new Random();
  198. while (i < pointList.size()) {
  199. int l = random.nextInt(4);
  200. if ((i + 1) % 8 != 0 && (i + 1) % 7 != 0 && i > 7 && i < 56) {
  201. if (pointList.get(i).getDirection() < 3) {
  202. if (l == 0 && pointList.get(i + 1).getDirection() >= 1) {
  203. pointList.get(i).setRight(1);
  204. pointList.get(i + 1).setLeft(1);
  205. } else if (l == 1 && pointList.get(i + 8).getDirection() >= 1) {
  206. pointList.get(i).setDown(1);
  207. pointList.get(i + 8).setUp(1);
  208. } else if (l == 2 && pointList.get(i - 1).getDirection() >= 1) {
  209. pointList.get(i).setLeft(1);
  210. pointList.get(i - 1).setRight(1);
  211. } else if (l == 3 && pointList.get(i - 8).getDirection() >= 1) {
  212. pointList.get(i).setUp(1);
  213. pointList.get(i - 8).setDown(1);
  214. }
  215. }
  216. }
  217. // 将数据存储到文件里面
  218. output.print(pointList.get(i).getUp());
  219. output.print(pointList.get(i).getRight());
  220. output.print(pointList.get(i).getDown());
  221. output.print(pointList.get(i).getLeft());
  222. output.print(' ');
  223. i++;
  224. if (i % 8 == 0) {
  225. output.println();
  226. }
  227. }
  228. output.close();
  229. }
  230. // 绘制寻找路径的行走路线
  231. private void paintMoveBall1(double i, double j, double m, double n) {
  232. Line line = new Line(i, j, m, n);
  233. line.setStrokeWidth(2.5);
  234. line.setFill(Color.GREENYELLOW);
  235. line.setStroke(Color.RED);
  236. pane.getChildren().add(line);
  237. }
  238. // 绘制遍历的行走路线
  239. private void paintMoveBall2(double i, double j, double m, double n) {
  240. Line line = new Line(i, j, m, n);
  241. line.setStrokeWidth(2.5);
  242. line.setFill(Color.GREENYELLOW);
  243. line.setStroke(Color.BLUE);
  244. pane.getChildren().add(line);
  245. }
  246. //绘制最短路径的行走路径
  247. private void paintMoveBall3(double i, double j, double m, double n){
  248. Line line = new Line(i, j, m, n);
  249. line.setStrokeWidth(4);
  250. line.setFill(Color.GREENYELLOW);
  251. line.setStroke(Color.CHARTREUSE);
  252. pane.getChildren().add(line);
  253. }
  254. // 迷宫地图数据导入栈
  255. private void inputMaze() {
  256. File file = new File("Maze.txt");
  257. Scanner input = null;
  258. while (!stack.empty()) {
  259. stack.pop();
  260. }
  261. stack.push(cell[ballCol][ballRaw]);// 将起点压入栈
  262. try {
  263. int i = 0;
  264. int j = 0;
  265. int n = 0;
  266. input = new Scanner(file);
  267. while (input.hasNext()) {
  268. String str = input.next();
  269. char a1 = str.charAt(0);
  270. int a = a1 - '0';
  271. char b1 = str.charAt(1);
  272. int b = b1 - '0';
  273. char c1 = str.charAt(2);
  274. int c = c1 - '0';
  275. char d1 = str.charAt(3);
  276. int d = d1 - '0';
  277. cell[i][j] = new cell(a, b, c, d);// 将迷宫地图数据存储到Cell[][]
  278. cell[i][j].setDix(n);
  279. n++;
  280. i++;
  281. if (i % 40 == 0) {
  282. i = 0;
  283. j++;
  284. }
  285. }
  286. } catch (Exception e) {
  287. e.printStackTrace();
  288. } finally {
  289. input.close();
  290. }
  291. }
  292. // 控制小球移动
  293. private void moveBall() {
  294. // 优先顺序,右左下上
  295. if (ballCol == 39 && ballRaw == 39) {
  296. animation.pause();
  297. } else if (stack.getSize() >= 0) {
  298. findWay();
  299. }
  300. }
  301. // 遍历迷宫时控制动画的函数
  302. private void travelMzae() {
  303. animation = new Timeline(new KeyFrame(Duration.millis(5), e1 -> travel()));
  304. animation.setCycleCount(Timeline.INDEFINITE);
  305. animation.play();
  306. }
  307. // 寻找最短路径时控制动画的函数
  308. private void samllWay() {
  309. animation = new Timeline(new KeyFrame(Duration.millis(10), e1 -> smallestWay()));
  310. animation.setCycleCount(Timeline.INDEFINITE);
  311. animation.play();
  312. }
  313. // 清空迷宫函数
  314. private void deleteMaze() {
  315. animation = null;
  316. pane.getChildren().clear();
  317. ballCol = 0; // 将行重新初始化
  318. ballRaw = 0; // 将列重新初始化
  319. while (!stack.empty()) {
  320. stack.pop();
  321. }
  322. }
  323. // 退出函数
  324. public void exit() {
  325. System.exit(0);
  326. }
  327. //寻找路径
  328. private void findWay() { // 利用右手法则来寻找路径
  329. cell[ballCol][ballRaw].setVisted(true);
  330. if (cell[ballCol][ballRaw].getRight() == 1 && cell[ballCol + 1][ballRaw].getLeft() == 1
  331. && cell[ballCol + 1][ballRaw].isVisted() == false && cell[ballCol + 1][ballRaw].isPass() == true) {// 右转
  332. stack.push(cell[ballCol][ballRaw]);
  333. cell[ballCol + 1][ballRaw].setVisted(true);
  334. double i = ball.getCenterX();
  335. double j = ball.getCenterY();
  336. ballCol++;
  337. ball.setCenterX(55 + ballCol * LENGTH);
  338. ball.setCenterY(55 + ballRaw * LENGTH);
  339. double m = ball.getCenterX();
  340. double n = ball.getCenterY();
  341. paintMoveBall1(i, j, m, n);
  342. } else if (ballCol > 0 && cell[ballCol][ballRaw].getLeft() == 1 && cell[ballCol - 1][ballRaw].getRight() == 1
  343. && cell[ballCol - 1][ballRaw].isVisted() == false && cell[ballCol - 1][ballRaw].isPass() == true) {// 左转
  344. stack.push(cell[ballCol][ballRaw]);
  345. cell[ballCol - 1][ballRaw].setVisted(true);
  346. double i = ball.getCenterX();
  347. double j = ball.getCenterY();
  348. ballCol--;
  349. ball.setCenterX(55 + ballCol * LENGTH);
  350. ball.setCenterY(55 + ballRaw * LENGTH);
  351. double m = ball.getCenterX();
  352. double n = ball.getCenterY();
  353. paintMoveBall1(i, j, m, n);
  354. } else if (cell[ballCol][ballRaw].getDown() == 1 && cell[ballCol][ballRaw + 1].getUp() == 1
  355. && cell[ballCol][ballRaw + 1].isVisted() == false && cell[ballCol][ballRaw + 1].isPass() == true) {// 下转
  356. stack.push(cell[ballCol][ballRaw]);
  357. cell[ballCol][ballRaw + 1].setVisted(true);
  358. double i = ball.getCenterX();
  359. double j = ball.getCenterY();
  360. ballRaw++;
  361. ball.setCenterX(55 + ballCol * LENGTH);
  362. ball.setCenterY(55 + ballRaw * LENGTH);
  363. double m = ball.getCenterX();
  364. double n = ball.getCenterY();
  365. paintMoveBall1(i, j, m, n);
  366. } else if (ballRaw > 0 && cell[ballCol][ballRaw].getUp() == 1 && cell[ballCol][ballRaw - 1].getDown() == 1
  367. && cell[ballCol][ballRaw - 1].isVisted() == false && cell[ballCol][ballRaw - 1].isPass() == true) {// 上转
  368. stack.push(cell[ballCol][ballRaw]);
  369. cell[ballCol][ballRaw - 1].setVisted(true);
  370. double i = ball.getCenterX();
  371. double j = ball.getCenterY();
  372. ballRaw--;
  373. ball.setCenterX(55 + ballCol * LENGTH);
  374. ball.setCenterY(55 + ballRaw * LENGTH);
  375. double m = ball.getCenterX();
  376. double n = ball.getCenterY();
  377. paintMoveBall1(i, j, m, n);
  378. } else { // 若四面都有墙,则删除栈顶的坐标,回到上一个访问的坐标
  379. cell cell1 = new cell();
  380. if (stack.getSize() > 0) {
  381. cell1 = stack.pop();
  382. for (int i = 0; i < 40; i++)
  383. for (int j = 0; j < 40; j++) {
  384. if (cell1.compareTo(cell[i][j]) == 0) {
  385. if (j > 1 && cell[i][j].getDir() == 0 && cell[i][j].getDirection() <= 1) {
  386. cell[i][j - 1].setPass();
  387. } else if (i < 39 && cell[i][j].getDir() == 1 && cell[i][j].getDirection() <= 1) {
  388. cell[i + 1][j].setPass();
  389. } else if (j < 39 && cell[i][j].getDir() == 2 && cell[i][j].getDirection() <= 1) {
  390. cell[i][j + 1].setPass();
  391. } else if (i > 0 && cell[i][j].getDir() == 3 && cell[i][j].getDirection() <= 1) {
  392. cell[i - 1][j].setPass();
  393. }
  394. ballCol = i;
  395. ballRaw = j;
  396. ball.setCenterX(55 + ballCol * LENGTH);
  397. ball.setCenterY(55 + ballRaw * LENGTH);
  398. break;
  399. }
  400. }
  401. }
  402. }
  403. }
  404. //遍历迷宫
  405. private void travel() {
  406. boolean visitedAll = true;
  407. for (int i = 0; i < cell.length; i++) {
  408. for (int j = 0; j < cell[i].length; j++) {
  409. if (cell[i][j].isVisted() == false)
  410. visitedAll = false;
  411. }
  412. }
  413. if (ballCol == 0 && ballRaw == 0 && visitedAll == true) {
  414. animation.stop();
  415. while (!stack.empty()) {
  416. stack.pop();
  417. }
  418. } else { //利用左手法则来遍历迷宫
  419. if (ballCol > 0 && cell[ballCol][ballRaw].getLeft() == 1 && cell[ballCol - 1][ballRaw].getRight() == 1
  420. && cell[ballCol - 1][ballRaw].isVisted() == false && cell[ballCol - 1][ballRaw].isPass() == true) {
  421. stack.push(cell[ballCol][ballRaw]);
  422. cell[ballCol - 1][ballRaw].setVisted(true);
  423. double i = ball.getCenterX();
  424. double j = ball.getCenterY();
  425. ballCol--;
  426. ball.setCenterX(55 + ballCol * LENGTH);
  427. ball.setCenterY(55 + ballRaw * LENGTH);
  428. double m = ball.getCenterX();
  429. double n = ball.getCenterY();
  430. paintMoveBall2(i, j, m, n);
  431. } else if (cell[ballCol][ballRaw].getRight() == 1 && cell[ballCol + 1][ballRaw].getLeft() == 1
  432. && cell[ballCol + 1][ballRaw].isVisted() == false && cell[ballCol + 1][ballRaw].isPass() == true) {
  433. stack.push(cell[ballCol][ballRaw]);
  434. cell[ballCol + 1][ballRaw].setVisted(true);
  435. double i = ball.getCenterX();
  436. double j = ball.getCenterY();
  437. ballCol++;
  438. ball.setCenterX(55 + ballCol * LENGTH);
  439. ball.setCenterY(55 + ballRaw * LENGTH);
  440. double m = ball.getCenterX();
  441. double n = ball.getCenterY();
  442. paintMoveBall2(i, j, m, n);
  443. } else if (ballRaw > 0 && cell[ballCol][ballRaw].getUp() == 1 && cell[ballCol][ballRaw - 1].getDown() == 1
  444. && cell[ballCol][ballRaw - 1].isVisted() == false && cell[ballCol][ballRaw - 1].isPass() == true) {
  445. stack.push(cell[ballCol][ballRaw]);
  446. cell[ballCol][ballRaw - 1].setVisted(true);
  447. double i = ball.getCenterX();
  448. double j = ball.getCenterY();
  449. ballRaw--;
  450. ball.setCenterX(55 + ballCol * LENGTH);
  451. ball.setCenterY(55 + ballRaw * LENGTH);
  452. double m = ball.getCenterX();
  453. double n = ball.getCenterY();
  454. paintMoveBall2(i, j, m, n);
  455. } else if (cell[ballCol][ballRaw].getDown() == 1 && cell[ballCol][ballRaw + 1].getUp() == 1
  456. && cell[ballCol][ballRaw + 1].isVisted() == false && cell[ballCol][ballRaw + 1].isPass() == true) {
  457. stack.push(cell[ballCol][ballRaw]);
  458. cell[ballCol][ballRaw + 1].setVisted(true);
  459. double i = ball.getCenterX();
  460. double j = ball.getCenterY();
  461. ballRaw++;
  462. ball.setCenterX(55 + ballCol * LENGTH);
  463. ball.setCenterY(55 + ballRaw * LENGTH);
  464. double m = ball.getCenterX();
  465. double n = ball.getCenterY();
  466. paintMoveBall2(i, j, m, n);
  467. } else {
  468. cell cell1 = new cell();
  469. if (stack.getSize() > 0) {
  470. cell1 = stack.pop();
  471. for (int i = 0; i < 40; i++)
  472. for (int j = 0; j < 40; j++) {
  473. if (cell1.compareTo(cell[i][j]) == 0) {
  474. if (j > 1 && cell[i][j].getDir() == 0 && cell[i][j].getDirection() <= 1) {
  475. cell[i][j - 1].setPass();
  476. } else if (i < 39 && cell[i][j].getDir() == 1 && cell[i][j].getDirection() <= 1) {
  477. cell[i + 1][j].setPass();
  478. } else if (j < 39 && cell[i][j].getDir() == 2 && cell[i][j].getDirection() <= 1) {
  479. cell[i][j + 1].setPass();
  480. } else if (i > 0 && cell[i][j].getDir() == 3 && cell[i][j].getDirection() <= 1) {
  481. cell[i - 1][j].setPass();
  482. }
  483. ballCol = i;
  484. ballRaw = j;
  485. ball.setCenterX(55 + ballCol * LENGTH);
  486. ball.setCenterY(55 + ballRaw * LENGTH);
  487. break;
  488. }
  489. }
  490. }
  491. }
  492. }
  493. }
  494. //最短路径
  495. private void smallestWay(){
  496. if(stack.empty()){
  497. findWay();
  498. }
  499. for(int i = 0;i<stack.getSize();i++){
  500. cell cell1 = new cell();
  501. cell cell2 = new cell();
  502. cell1 = stack.peeknew(i);
  503. cell2 = stack.peeknew(i+1);
  504. int k = ((cell1.getX()+1)*LENGTH)-5;
  505. int j = ((cell1.getY()+1)*LENGTH)-5;
  506. int m = ((cell2.getX()+1)*LENGTH)-5;
  507. int n = ((cell2.getY()+1)*LENGTH)-5;
  508. paintMoveBall3(k,j,m,n);
  509. }
  510. }
  511. }

3.1.2 Maze类

主要用于创建迷宫。迷宫的每个单元格长度为10,且迷宫长度为40*40。类中提供各个数据的访问器和修改器。

  1. package io.github.xieyezi;
  2. import java.util.ArrayList;
  3. import java.util.Random;
  4. public class Maze
  5. {
  6. private int width = 40;// 迷宫宽度
  7. private int height = 40;// 迷宫高度
  8. private Random rnd = new Random();//用于创建迷宫时随机访问下一个点
  9. public Maze()
  10. {
  11. }
  12. public int getWidth()
  13. {
  14. return width;
  15. }
  16. public void setWidth(int width)
  17. {
  18. this.width = width;
  19. }
  20. public int getHeight()
  21. {
  22. return height;
  23. }
  24. public void setHeight(int height)
  25. {
  26. this.height = height;
  27. }
  28. public Maze(int width, int height)
  29. {
  30. super();
  31. this.width = width;
  32. this.height = height;
  33. }
  34. public ArrayList<mazePoint> getMaze()
  35. {
  36. ArrayList<mazePoint> maze = new ArrayList<mazePoint>();
  37. for (int h = 0; h < height; h++)
  38. {
  39. for (int w = 0; w < width; w++)
  40. {
  41. mazePoint point = new mazePoint(w, h);
  42. maze.add(point);
  43. }
  44. }
  45. return CreateMaze(maze);
  46. }
  47. //创建迷宫
  48. private ArrayList<mazePoint> CreateMaze(ArrayList<mazePoint> maze)
  49. {
  50. int top = 0;
  51. int x = 0;
  52. int y = 0;
  53. ArrayList<mazePoint> team = new ArrayList<mazePoint>();
  54. team.add(maze.get(x + y * width));
  55. while (top >= 0)
  56. {
  57. int[] val = new int[]
  58. { -1, -1, -1, -1 };
  59. int times = 0;
  60. boolean flag = false;
  61. mazePoint pt = (mazePoint) team.get(top);
  62. x = pt.getX();
  63. y = pt.getY();
  64. pt.visted = true;// 记录单元格已访问
  65. ro1: while (times < 4)
  66. {
  67. int dir = rnd.nextInt(4);
  68. if (val[dir] == dir)
  69. continue;
  70. else
  71. val[dir] = dir;
  72. switch (dir)
  73. {
  74. case 0: // 左边
  75. if ((x - 1) >= 0 && maze.get(x - 1 + y * width).visted == false)
  76. {
  77. if (x == 0 && y == 0 || x == width && y == height)
  78. {
  79. top++;
  80. flag = true;
  81. break;
  82. }
  83. maze.get(x + y * width).setLeft();
  84. maze.get(x - 1 + y * width).setRight();
  85. team.add(maze.get(x - 1 + y * width));
  86. top++;
  87. flag = true;
  88. break ro1;
  89. }
  90. break;
  91. case 1: // 右边
  92. if ((x + 1) < width && maze.get(x + 1 + y * width).visted == false)
  93. {
  94. maze.get(x + y * width).setRight();
  95. maze.get(x + 1 + y * width).setLeft();
  96. team.add(maze.get(x + 1 + y * width));
  97. top++;
  98. flag = true;
  99. break ro1;
  100. }
  101. break;
  102. case 2: // 上边
  103. if ((y - 1) >= 0 && maze.get(x + (y - 1) * width).visted == false)
  104. {
  105. maze.get(x + y * width).setUp();
  106. maze.get(x + (y - 1) * width).setDown();
  107. team.add(maze.get(x + (y - 1) * width));
  108. top++;
  109. flag = true;
  110. break ro1;
  111. }
  112. break;
  113. case 3: // 下边
  114. if ((y + 1) < height && maze.get(x + (y + 1) * width).visted == false)
  115. {
  116. maze.get(x + y * width).setDown();
  117. maze.get(x + (y + 1) * width).setUp();
  118. team.add(maze.get(x + (y + 1) * width));
  119. top++;
  120. flag = true;
  121. break ro1;
  122. }
  123. break;
  124. }
  125. times++;
  126. }
  127. if (!flag)
  128. {
  129. team.remove(top);
  130. top -= 1;
  131. }
  132. }
  133. int t = 0;
  134. while (t<maze.size())
  135. {
  136. maze.get(t).setDirection();
  137. t++;
  138. }
  139. return maze;
  140. }
  141. }

3.1.3 mazePoint类

主要用于表示迷宫里面每一个点。每一个点都有上下左右四个属性,在迷宫中的坐标,还有每个点四面空白墙壁的数量。类中提供各个数据的访问器和修改器。

  1. package io.github.xieyezi;
  2. public class mazePoint
  3. {
  4. // “0”表示有墙,“1”表示无墙
  5. private int left = 0;
  6. private int right = 0;
  7. private int up = 0;
  8. private int down = 0;
  9. // 迷宫中的坐标
  10. private int x;
  11. private int y;
  12. public boolean visted;
  13. // 周围空白墙壁的数量
  14. private int direction = 0;
  15. public mazePoint(int x, int y)
  16. {
  17. this.x = x;
  18. this.y = y;
  19. }
  20. public int getLeft()
  21. {
  22. return left;
  23. }
  24. public void setLeft()
  25. {
  26. this.left = 1;
  27. }
  28. public int getRight()
  29. {
  30. return right;
  31. }
  32. public void setRight()
  33. {
  34. this.right = 1;
  35. }
  36. public int getUp()
  37. {
  38. return up;
  39. }
  40. public void setUp()
  41. {
  42. this.up = 1;
  43. }
  44. public int getDown()
  45. {
  46. return down;
  47. }
  48. public void setDown()
  49. {
  50. this.down = 1;
  51. }
  52. public void setLeft(int left)
  53. {
  54. this.left = left;
  55. }
  56. public void setRight(int right)
  57. {
  58. this.right = right;
  59. }
  60. public void setUp(int up)
  61. {
  62. this.up = up;
  63. }
  64. public void setDown(int down)
  65. {
  66. this.down = down;
  67. }
  68. public int getX()
  69. {
  70. return x;
  71. }
  72. public void setX(int x)
  73. {
  74. this.x = x;
  75. }
  76. public int getY()
  77. {
  78. return y;
  79. }
  80. public void setY(int y)
  81. {
  82. this.y = y;
  83. }
  84. public int getDirection()
  85. {
  86. return direction;
  87. }
  88. public void setDirection()
  89. {
  90. if (this.up == 1)
  91. this.direction++;
  92. if (this.right == 1)
  93. this.direction++;
  94. if (this.down == 1)
  95. this.direction++;
  96. if (this.left == 1)
  97. this.direction++;
  98. }
  99. }

3.1.4 cell类

主要用于表示迷宫里面每一个单元格。每个单元格都有上下左右四个属性,在迷宫中的行列坐标,访问标记,以及每个单元格四面空白墙壁的数量。类中提供各个数据的访问器和修改器。

  1. package io.github.xieyezi;
  2. public class cell implements Comparable<cell>
  3. {
  4. // “0”表示有墙,“1”表示无墙
  5. private int left = 1;
  6. private int right = 1;
  7. private int up = 1;
  8. private int down = 1;
  9. private int dir;// 小球前进的方向,0,1,2,3分别代表上右下左
  10. private int destion;// 存储单元格的位置
  11. // 迷宫中的行列坐标
  12. private int x;
  13. private int y;
  14. public boolean visted = false; //单元格的访问标记
  15. private boolean pass = true;//是否为死路
  16. private int direction = 0; //周围空白墙壁的数量
  17. public cell()
  18. {
  19. x = 0;
  20. y = 0;
  21. }
  22. public cell(int x, int y)
  23. {
  24. this.x = x;
  25. this.y = y;
  26. this.pass=true;
  27. }
  28. public cell(int up, int right, int down, int left)
  29. {
  30. this.up = up;
  31. this.right = right;
  32. this.down = down;
  33. this.left = left;
  34. this.pass=true;
  35. setDirection();
  36. }
  37. public int getLeft()
  38. {
  39. return left;
  40. }
  41. public void setLeft(int left)
  42. {
  43. this.left = left;
  44. }
  45. public int getRight()
  46. {
  47. return right;
  48. }
  49. public void setRight(int right)
  50. {
  51. this.right = right;
  52. }
  53. public int getUp()
  54. {
  55. return up;
  56. }
  57. public void setUp(int up)
  58. {
  59. this.up = up;
  60. }
  61. public int getDown()
  62. {
  63. return down;
  64. }
  65. public void setDown(int down)
  66. {
  67. this.down = down;
  68. }
  69. public int getX()
  70. {
  71. return x;
  72. }
  73. public void setX(int x)
  74. {
  75. this.x = x;
  76. }
  77. public int getY()
  78. {
  79. return y;
  80. }
  81. public void setY(int y)
  82. {
  83. this.y = y;
  84. }
  85. public boolean isVisted()
  86. {
  87. return visted;
  88. }
  89. public void setVisted(boolean visted)
  90. {
  91. this.visted = visted;
  92. }
  93. public int getDir()
  94. {
  95. return dir;
  96. }
  97. public void setDir(int dir)
  98. {
  99. this.dir = dir;
  100. }
  101. public int compareTo(cell o)
  102. {
  103. return this.destion - o.getDix();
  104. }
  105. public int getDix()
  106. {
  107. return destion;
  108. }
  109. public void setDix(int dix)
  110. {
  111. this.destion = dix;
  112. }
  113. public boolean isPass()
  114. {
  115. return pass;
  116. }
  117. public void setPass()
  118. {
  119. this.pass = false;
  120. }
  121. public int getDirection()
  122. {
  123. return direction;
  124. }
  125. public void setDirection()
  126. {
  127. if (this.up == 1)
  128. this.direction++;
  129. if (this.right == 1)
  130. this.direction++;
  131. if (this.down == 1)
  132. this.direction++;
  133. if (this.left == 1)
  134. this.direction++;
  135. }
  136. }

3.1.5 myStack类

主要用于存储单元格的行列坐标。利用一个cell类的数组来存储单元格的坐标,栈的默认长度为1600。类中提供各个数据的访问器和修改器。

  1. package io.github.xieyezi;
  2. public class myStack
  3. {
  4. private cell[] elements;
  5. private int size;//栈的长度
  6. public static final int Default_capacity = 1600; //默认长度为1600
  7. public myStack()
  8. {
  9. elements = new cell[Default_capacity];
  10. }
  11. //把一个点压入栈中
  12. public void push(cell value)
  13. {
  14. elements[size++] = value;
  15. }
  16. //删除栈顶的点并返回它
  17. public cell pop()
  18. {
  19. return elements[--size];
  20. }
  21. //返回栈顶的点
  22. public cell peek()
  23. {
  24. return elements[size - 1];
  25. }
  26. //返回栈中指定的点
  27. public cell peeknew(int i)
  28. {
  29. return elements[i];
  30. }
  31. //判断栈是否为空
  32. public boolean empty()
  33. {
  34. return size == 0;
  35. }
  36. //返回栈的长度
  37. public int getSize()
  38. {
  39. return size;
  40. }
  41. }

3.2 绘制迷宫的实现

利用Line类创建,先画出坐标轴的线。然后再根据每个点四个面的信息画线。

3.3 动画效果的实现

创建一个TimeLine类的对象,利用模拟的小球圆心坐标的移动画线,从而展示出动态的效果。

3.4 清空迷宫的实现

利用面板的clear()方法清除装迷宫面板即可。

3.5 退出游戏的实现

利用exit()退出游戏即可。

上传的附件 cloud_download 基于Java的迷宫游戏.zip ( 311.20kb, 123次下载 )
error_outline 下载需要2点积分

发送私信

成功其实很简单,就是当你坚持不住的时候,再坚持一下

9
文章数
8
评论数
最近文章
eject