一、实验内容:

1)迷宫游戏是非常经典的游戏,在该题中要求随机生成一个迷宫,并求解迷宫;

2) 要求查找并理解迷宫生成的算法,并尝试用两种不同的算法来生成随机的迷宫。

  1. 要求迷宫游戏支持玩家走迷宫,和系统走迷宫路径两种模式。玩家走迷宫,通过键盘方向键控制,并在行走路径上留下痕迹;系统提示迷宫路径要求基于A*算法实现,输出玩家当前位置到迷宫出口的最优路径。设计交互友好的游戏图形界面。

二、深度优先算法生成迷宫

1、整体思路

1)利用深度遍历的思想。访问到一个节点时,搜索这个节点没有被访问过的相邻节点,选择一个继续做同样的操作,直到没有邻节点为止再回溯到上一个访问的节点,并选择另外的邻节点。

2)这种方案生成的迷宫会有一条明显的主路,这条主路特别长,贯穿大部分区域的路线,同时,迷宫的路线一般比较扭曲。这种采用深度优先算法(递归回溯算法)生成的迷宫称之为“主路扭曲型”迷宫。

三、深度优先搜索实现寻路功能

选定格子作为根节点,从它开始随机地深度搜索前进,开出一条路来,直到无路可走了,退回一步,换另一条路,再走到无路可走,回退一步,换另一条。如此循环往复,直到完全无路可走。

选择一个格子根节点,将它压进栈里。然后在栈不为空的时候执行以下循环:

取出一个格子,将它的INTREE标志设置为1,然后将它的所有不在树中的邻居格子压进栈里(顺序随机),并且让这些邻居格子的father指向该格子。

二、代码分析

一、子方格对象类的创建:

我们需要把大的窗口分割为n×n个子方块,对方块类创建的的方格对象进行操作,使得各子方块具有更多的方法和属性,就要用子方块类创建子方块对象,并设计相关的方法,获取和修改各子方块对象的属性。

1、网格类grid的创建以及其构造函数的,坐标变量,标志位,以及父节点对象的初始设置;

class Lattice {static final int INTREE = 1;static final int NOTINTREE = 0;private final int x; // 格子的位置,在第几行private final int y; // 第几列private int flag = NOTINTREE; // flag,标识格子是否已加入树中private Lattice father = null; // 格子的父亲节点public Lattice(int xx, int yy) {x = xx;y = yy;}

2、比如基本的坐标获取方法:

 public int getX() {return x;}public int getY() {return y;}

3、标志位的获取和修改方法;

  public int getFlag() {return flag;}  public void setFlag(int f) {flag = f;}

4、父节点对象的获取和修改;

   public grid getFather() {                 //获取方格对象的父节点;return father;}public void setFather(grid f) {           //修改方格对象的父节点;father = f;}

二、迷宫Maze类的设计;

(1)、类的声明以及基本变量设置;

1、创建迷宫类继承 JPanel类;

2、关于迷宫窗口的长宽、方格数目,边距宽度

3、将整个窗口定义位一个网格类二维矩阵;设置相关变量;

class Maze extends JPanel {//private static final long serialVersionUID = -8300339045454852626L;private final int NUM;//num是数组和地图的边长,private final int width;//width 每个格子的宽度和高度;private final int padding;//地图面板的大小;private final Lattice[][] maze;//lattic类的数组maze,用于保存每个格子;private int ballX, ballY;//起始位置坐标;private boolean drawPath = false; // flag,标识是否画出路径

2、迷宫类的构造函数:

建立二重循环,对二维矩阵的迷宫内部按照方格分别定义n×n个网格对象;

后续调用创建迷宫和按键监视器得操作得方法。

 Maze(int m, int wi, int p) {NUM = m;width = wi;padding = p;maze = new Lattice[NUM][NUM];for (int i = 0; i <= NUM - 1; i++)for (int j = 0; j <= NUM - 1; j++)maze[i][j] = new Lattice(i, j);createMaze();setKeyListener();this.setFocusable(true);}

3、迷宫得默认构造方法:

1、对每个子方格对象的构造,通过循环,设置每个子方格对象的父节点位null,标志位为非入树的空状态;

2、设置初始的位置坐标(myX,myY);

3、将路径标识位也置为false状态;

4、设置控件获取焦点;

 // 初始化游戏,重开一局时使用private void init() {for (int i = 0; i <= NUM - 1; i++)for (int j = 0; j <= NUM - 1; j++) {maze[i][j].setFather(null);maze[i][j].setFlag(Lattice.NOTINTREE);}ballX = 0;ballY = 0;drawPath = false;createMaze();// setKeyListener();this.setFocusable(true);repaint();}

5、根据子网格对象的坐标获取和直接由对象获取坐标的信息的四个方法:

(由于私有变量只能通过对象调用函数访问)

四、源代码

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import java.util.Stack;
import javax.swing.*;
class Lattice {static final int INTREE = 1;static final int NOTINTREE = 0;private final int x; // 格子的位置,在第几行private final int y; // 第几列private int flag = NOTINTREE; // flag,标识格子是否已加入树中private Lattice father = null; // 格子的父亲节点public Lattice(int xx, int yy) {x = xx;y = yy;}public int getX() {return x;}public int getY() {return y;}public int getFlag() {return flag;}public Lattice getFather() {return father;}public void setFather(Lattice f) {father = f;}public void setFlag(int f) {flag = f;}public String toString() {return "(" + x + "," + y + ")\n";}
}
class Maze extends JPanel {//private static final long serialVersionUID = -8300339045454852626L;private final int NUM;//num是数组和地图的边长,private final int width;//width 每个格子的宽度和高度;private final int padding;//地图面板的大小;private final Lattice[][] maze;//lattic类的数组maze,用于保存每个格子;private int ballX, ballY;//起始位置坐标;private boolean drawPath = false; // flag,标识是否画出路径Maze(int m, int wi, int p) {NUM = m;width = wi;padding = p;maze = new Lattice[NUM][NUM];for (int i = 0; i <= NUM - 1; i++)for (int j = 0; j <= NUM - 1; j++)maze[i][j] = new Lattice(i, j);createMaze();setKeyListener();this.setFocusable(true);}// 初始化游戏,重开一局时使用private void init() {for (int i = 0; i <= NUM - 1; i++)for (int j = 0; j <= NUM - 1; j++) {maze[i][j].setFather(null);maze[i][j].setFlag(Lattice.NOTINTREE);}ballX = 0;ballY = 0;drawPath = false;createMaze();// setKeyListener();this.setFocusable(true);repaint();}// 由格子的行数,得到格子中心点的像素X坐标public int getCenterX(int x) {return padding + x * width + width / 2;}// 由格子的列数,得到格子中心点的像素Y坐标public int getCenterY(int y) {return padding + y * width + width / 2;}public int getCenterX(Lattice p) {return padding + p.getY() * width + width / 2;}public int getCenterY(Lattice p) {return padding + p.getX() * width + width / 2;}// 检查是否到达最后一个格子,若是则走出了迷宫,重开一局游戏private void checkIsWin() {if (ballX == NUM - 1 && ballY == NUM - 1) {JOptionPane.showMessageDialog(null, "你赢了!", "迷宫小游戏",JOptionPane.PLAIN_MESSAGE);init();}}// 移动小球,c为按键码synchronized private void move(int c) {int tx = ballX, ty = ballY;// System.out.println(c);switch (c) {case KeyEvent.VK_LEFT -> ty--;case KeyEvent.VK_RIGHT -> ty++;case KeyEvent.VK_UP -> tx--;case KeyEvent.VK_DOWN -> tx++;case KeyEvent.VK_SPACE -> drawPath = !drawPath;default -> {}}// 若移动后未出界且格子之间有路径,则进行移动,更新小球位置,否则移动非法if (!isOutOfBorder(tx, ty)&& (maze[tx][ty].getFather() == maze[ballX][ballY]|| maze[ballX][ballY].getFather() == maze[tx][ty])) {ballX = tx;ballY = ty;}}private void setKeyListener() {this.addKeyListener(new KeyAdapter() {public void keyPressed(KeyEvent e) {int c = e.getKeyCode();move(c);repaint();checkIsWin();}});}// 是否出界private boolean isOutOfBorder(Lattice p) {return isOutOfBorder(p.getX(), p.getY());}private boolean isOutOfBorder(int x, int y) {return x > NUM - 1 || y > NUM - 1 || x < 0 || y < 0;}// 获取格子的邻居格子private Lattice[] getNeis(Lattice p) {final int[] adds = {-1, 0, 1, 0, -1};if (isOutOfBorder(p)) {return null;}Lattice[] ps = new Lattice[4]; // 四个邻居格子,顺序为上右下左,出界的邻居为nullint xt;int yt;for (int i = 0; i <= 3; i++) {xt = p.getX() + adds[i];yt = p.getY() + adds[i + 1];if (isOutOfBorder(xt, yt))continue;ps[i] = maze[xt][yt];}return ps;}// 构建随机树,创建迷宫private void createMaze() {// 随机选一个格子作为树的根Random random = new Random();int rx = NUM-1;int ry =  NUM-1;// 深度优先遍历Stack<Lattice> s = new Stack<>();Lattice p = maze[rx][ry];Lattice[] neis;s.push(p);//根节点压入栈中;while (!s.isEmpty()) {//如果栈不是空;p = s.pop();//推出栈顶;p.setFlag(Lattice.INTREE);//标志在栈内。neis = getNeis(p);//遍历周围的格子;放进数组;int ran = Math.abs(random.nextInt());//随机生成一个数;for (int a = 0; a <= 3; a++) {//生成树;ran++;ran %= 4;//ran的值永远是0,1,2,3。assert neis != null;if (neis[ran] == null || neis[ran].getFlag() == Lattice.INTREE)//节点附近的节点有出界或者在树内;continue;s.push(neis[ran]);//否则压入栈;neis[ran].setFather(p);//记录父节点;}}}// 抹掉两个格子之间的边private void clearFence(int i, int j, int fx, int fy, Graphics g) {int sx = padding + ((Math.max(j, fy)) * width),sy = padding + ((Math.max(i, fx)) * width),dx = (i == fx ? sx : sx + width),dy = (i == fx ? sy + width : sy);if (sx != dx) {sx++;dx--;} else {sy++;dy--;}g.drawLine(sx, sy, dx, dy);}protected void paintComponent(Graphics g) {//画网格super.paintComponent(g);g.setColor(Color.black);for (int i = 0; i <= NUM; i++) {//画横线g.drawLine(padding + i * width, padding, padding + i * width,padding + NUM * width);}for (int j = 0; j <= NUM; j++) {//画竖线g.drawLine(padding, padding + j * width, padding + NUM * width,padding + j * width);}g.setColor(this.getBackground());//用背景色覆盖for (int i = NUM - 1; i >= 0; i--) {for (int j = NUM - 1; j >= 0; j--) {Lattice f = maze[i][j].getFather();if (f != null) {int fx = f.getX(), fy = f.getY();clearFence(i, j, fx, fy,g);}}}g.drawLine(padding, padding + 1, padding, padding + width - 1);int last = padding + NUM * width;g.drawLine(last, last - 1, last, last - width + 1);g.setColor(Color.orange);g.fillOval(getCenterX(ballY) - width / 3, getCenterY(ballX) - width / 3,width / 2, width / 2);if (drawPath) drawPath(g);}private void drawPath(Graphics g) {if (drawPath)g.setColor(Color.orange);Lattice p = maze[0][0];//入口格子为对象while (p.getFather() != null) {g.drawLine(getCenterX(p), getCenterY(p), getCenterX(p.getFather()),getCenterY(p.getFather()));p = p.getFather();}g.fillOval(getCenterX(p) - width / 3, getCenterY(p) - width / 3,width / 2, width / 2);//设置末尾圆点位置;p = maze[NUM - 1][NUM - 1];//出口格子为对象while (p.getFather() != null) {if (p.getFlag() == 3)break;g.drawLine(getCenterX(p), getCenterY(p), getCenterX(p.getFather()),getCenterY(p.getFather()));//画出父子节点之间的通路;p = p.getFather();}}
}
class Cal extends JFrame implements ActionListener{public static void main(String[] args) {final int  LX1 = 800, LY1 = 300;JPanel pan = new JPanel();//创建容器;pan.setBounds(20,40,240,280);JLabel pan4=new JLabel("迷宫小游戏");pan4.setHorizontalAlignment(SwingConstants.CENTER);//JButton pan1=new JButton("简单模式");//按钮显示;JButton pan2=new JButton("开始游戏");//JButton pan3=new JButton("困难模式");GridLayout grid2 = new GridLayout(2, 1);pan.setLayout(grid2);//容器分割为四行,用于存放按钮。pan.add(pan4);//pan.add(pan1);//按钮加入容器中。pan.add(pan2);//pan.add(pan3);Cal frame1 = new Cal();//创建Cal类的对象frame1.frame1.setTitle("迷宫小游戏");//设置框架标题。frame1.add(pan);//pan容器加入框架;frame1.setLayout(null);//设置容器与框架边界有间隔。frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//默认关闭;frame1.setSize(300, 400 );frame1.setLocation(LX1, LY1);//frame1在屏幕的显示位置;frame1.setVisible(true);//框架可视化;frame1.setResizable(false);//大小不可更改;//pan1.addActionListener(frame1);pan2.addActionListener(frame1);//按钮加入侦听;//pan3.addActionListener(frame1);}@Overridepublic void actionPerformed(ActionEvent e) {/*if(e.getActionCommand().equals("简单模式")) {final int n = 20, width = 600, padding = 30, LX = 700, LY = 100;JPanel p = new Maze(n, (width - padding - padding) / n, padding);JFrame frame = new JFrame("迷宫小游戏 简单模式");frame.getContentPane().add(p);frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);frame.setSize(width + padding, width + padding + padding);frame.setLocation(LX, LY);frame.setVisible(true);frame.setResizable(false);}*/if(e.getActionCommand().equals("开始游戏")) {final int n = 30, width = 700, padding = 25, LX = 700, LY = 100;//设定大小;JPanel p = new Maze(n, (width - padding - padding) / n, padding);//生成迷宫;JFrame frame = new JFrame("迷宫小游戏");frame.getContentPane().add(p);//迷宫容器加入frame.frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);frame.setSize(width + padding, width + padding + padding);//设置frame的大小。frame.setLocation(LX, LY);//屏幕上的显示位置;frame.setVisible(true);//可视化;frame.setResizable(false);}/*if(e.getActionCommand().equals("困难模式")) {final int n = 50, width = 800, padding = 20, LX = 400, LY = 50;JPanel p = new Maze(n, (width - padding - padding) / n, padding);JFrame frame = new JFrame("迷宫小游戏 困难模式");frame.getContentPane().add(p);frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);frame.setSize(width + padding, width + padding + padding);frame.setLocation(LX, LY);frame.setVisible(true);frame.setResizable(false);}*/}
}

基于Java的迷宫小游戏相关推荐

  1. 基于java的俄罗斯方块小游戏设计(含源文件)

    欢迎添加微信互相交流学习哦! 项目源码:https://gitee.com/oklongmm/biye 题 目          小游戏开发 摘    要     俄罗斯方块是我们最常见的游戏之一,该 ...

  2. 连连看游戏的设计与实现——基于JAVA语言的小游戏

    说明:本篇博客主要讲述练练看游戏的设计与实现.前半部分为分析与类和属性的说明,后半部分为程序的实现与程序代码.第一次写小游戏,仍存在许多问题,也借鉴了CSDN前辈的代码想法,如有不妥,还望多批评指正. ...

  3. java写华容道_基于java的华容道小游戏

    一.华容道游戏简介 华容道,古老的中国游戏,以其变化多端.百玩不厌的特点与魔方.独立钻石棋一起被国外智力专家并称为"智力游戏界的三个不可思议".它与七巧板.九连环等中国传统益智玩具 ...

  4. 基于java的华容道小游戏

    一.华容道游戏简介 华容道,古老的中国游戏,以其变化多端.百玩不厌的特点与魔方.独立钻石棋一起被国外智力专家并称为"智力游戏界的三个不可思议".它与七巧板.九连环等中国传统益智玩具 ...

  5. java游戏界面制作_软件设计之基于Java的连连看小游戏(二)——游戏基础界面的制作及事件的添加...

    上次完成到游戏首页的制作,今天完成了游戏基础界面的制作以及事件的简单添加.由于功能尚未完全实现,因此游戏界面的菜单列表只是简单地添加了一下,其余菜单列表以及倒计时等在后续的制作中逐一完善. 1.首先在 ...

  6. 基于Java坦克大战小游戏设计 (2)

    接下来继续完善element下物体类,以及添加有关整体游戏进程.配置.绘画相关的类. game包:GameRunThread线程用来开始并处理游戏运行中出现的各种事件,继承thread类. publi ...

  7. 基于Java坦克大战小游戏设计(1)

    还是采用上学期学习到的设计模式,抽点时间写下这个游戏,游戏逻辑部分先写简单一点的,主要想加深对java设计.模块化等方面的理解. 首先先写Element包下各个元素的类:包括子弹.坦克.树木.河流.家 ...

  8. 基于HTML5的WebGL实现的2D3D迷宫小游戏

    为了实现一个基于HTML5的场景小游戏,我采用了HT for Web来实现,短短200行代码,我就能实现用"第一人称"来操作前进后退上下左右,并且实现了碰撞检测. 先来看下实现的效 ...

  9. java毕业设计——基于java+J2ME的堡垒游戏设计与实现(毕业论文+程序源码)——堡垒游戏

    基于java+J2ME的堡垒游戏设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+J2ME的堡垒游戏设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦. 文章目录: 基于ja ...

最新文章

  1. python知识点:文件读写以及其他基础知识点
  2. html 一条线两种颜色,HTML5/CSS3超酷进度条 不同进度多种颜色
  3. 爬虫--用python中requests和urllib模块爬取图片
  4. python中文显示不出来_Python数据可视化利器Matplotlib,无法显示中文,怎么办?...
  5. 【转】从零开始学图形学:10分钟看懂贝塞尔曲线
  6. java通用异常_Java常用异常整理
  7. IOS 7 Xcode 5 免IDP证书 真机调试
  8. .aspx(或.asp)文件与.html(.htm)文件的区别与联系
  9. 杭州电子科技大学程序设计竞赛(2016’12)- 网络同步赛 1004
  10. 平面构成之形式美与要素
  11. 李宏毅2020机器学习课程笔记(一)
  12. 2022年湖南省临床执业医师考试二单元随机真题
  13. 关于“Connection refused: connect”错误
  14. 2022陕西最新建筑八大员(土建)模拟考试题库及答案
  15. java自行车租凭系统项目包_基于jsp的自行车租赁-JavaEE实现自行车租赁 - java项目源码...
  16. PTGui Pro 12(全景图合成软件)官方中文版V12.0 | PTGui汉化版下载 | PTGUi官网下载
  17. IDC:机房监控系统
  18. Java 帕斯卡三角/杨辉三角
  19. imac卸载_如何从较旧的2007-2009 iMac上卸下光盘驱动器
  20. 进程与线程之间的联系和区别

热门文章

  1. excel批量删除单元格中的部分内容;批量在单元格内容首尾添加字符
  2. 球球大作战四亿人都在玩?玩家回归没有优越感,新玩家游戏被虐,游戏体验感极差!...
  3. 什么是显卡?为什么计算机要有显卡?
  4. 我是如何把性能优化的颗粒度做的更细
  5. windows7系统10个常用技巧概述
  6. 本地markdown文件自动生成|图片批量压缩并转base64格式|告别图床服务器|博文神器
  7. vue设置首页不经过路由,直接使用自定义的html页面
  8. OpenGL 学习笔记 II:初始化 API,第一个黑窗,游戏循环和帧率,OpenGL 默认垂直同步,glfw 帧率
  9. JDK1.7 ImageIO的一个梗
  10. 子弹短信iOS版本全面下架,罗永浩啪啪啪又被打脸?