2020-12-13

Java实现迷宫的过程

实验目的

(1)了解JavaGUI编程的窗体,菜单,熟悉Java的事件委托处理,能完成键盘的事件处理;
(2)熟悉Java中的绘图操作,使用绘图函数进行图形的绘制和重绘等基本操作;
(3)熟悉模块的划分以及游戏类的编写,了解相关的游戏设计和实现模式;
(4)使用深度搜索算法实现迷宫游戏和生成迷宫路径。

实验前的内容预习与准备

JavaGUI编程;鼠标和键盘的事件处理,Java图形界面编程。

实验过程

1.功能分析

根据对游戏系统进行需求分析,迷宫设计可以分为五个部分:迷宫主界面、计时窗口、迷宫设计、道路和障碍设计、出入口设计。
系统功能图如下
在这里插入图片描述

2.迷宫系统流程图在这里插入图片描述
3.实现功能的主要算法

使用深度搜索算法:随机选择一个格子作为根节点,从它开始随机地深度搜索前进,开出一条路来,直到无路可走了,退回一步,换另一条路,再走到无路可走,回退一步,换另一条……如此循环往复,直到完全无路可走。
深度搜索,用一个数组存放产生的所有状态。
(1) 把初始状态放入数组中,设为当前状态;
(2) 扩展当前的状态,产生一个新的状态放入数组中,同时把新产生的状态设为当前状态;
(3) 判断当前状态是否和前面的重复,如果重复则回到上一个状态,产生它的另一状态;
(4) 判断当前状态是否为目标状态,如果是目标,则找到一个解答,结束算法。
(5) 如果数组为空,说明无解。

4.程序实现的主要方法

两个类grid和类Maze的程序模块图如下:
在这里插入图片描述
在这里插入图片描述

第一步:界面大小初始化,构建迷宫基本样貌

  private int NUM, width, heigth;// width和heigth为每个格子的宽度和高度
  private Lattice[][] maze;//定义一个二维数组
  private int ballX, ballY;//定义位置
  private boolean drawPath = false;//迷宫的路径不可以改变
  Maze(int m, int wi, int p) {//迷宫函数定义给宽度和高度初始大小赋值   
     NUM = m;
    width = wi;//宽度赋值为wi
    heigth = h;//高度赋值为h
    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);//将lattice中的值赋值给maze
    createMaze();
    setKeyListener();
    this.setFocusable(true);

第二步:生成随机路径

while (!s.isEmpty()) {//判断下一步是否为空
      p = s.pop();
      p.setFlag(grid.going1);
      neis = getNeis(p);
      int ran = Math.abs(random.nextInt()) % 4;
      for (int a = 0; a <= 3; a++) {
        ran++;
        ran %= 4;
        if (neis[ran] == null || neis[ran].getFlag() == grid.going1)
          continue;
        s.push(neis[ran]);
        neis[ran].setFather(p);
      }

第三步:深度搜索遍历树算法构建迷宫和寻找节点的过程

private void createMaze() {//构建迷宫
    Random random = new Random();
    int rx = Math.abs(random.nextInt()) % NUM;//小圆点的x坐标
    int ry = Math.abs(random.nextInt()) % NUM;//小圆点的y坐标
    Stack<grid> s = new Stack<grid>();
    grid p = maze[rx][ry];//更新坐标
    grid neis[] = null;
    s.push(p);
 private void changeFather(grid p, grid f) {//改变该节点的前继节点,寻找该节点的下一个前继节点
    if (p.getFather() == null) {
      p.setFather(f);
      return;
    } else {
      changeFather(p.getFather(), p);
    }
  }

第四步:实现四个方向的运动

```java
synchronized private void move(int c) {
    int tx = ballX, ty = ballY;
    // System.out.println(c);
    switch (c) {
      case KeyEvent.VK_LEFT :
        ty--;
        break;
      case KeyEvent.VK_RIGHT :
        ty++;
        break;
      case KeyEvent.VK_UP :
        tx--;
        break;
      case KeyEvent.VK_DOWN :
        tx++;
        break;
      case KeyEvent.VK_SPACE :
        if (drawPath == true) {
          drawPath = false;
        } else {
          drawPath = true;
        }
        break;

第五步:设置键盘按键事件监听

private void setKeyListener() {
    this.addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        int c = e.getKeyCode();
        move(c);
        repaint();
        checkIsWin();
 private boolean isOutOfBorder(grid 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) ? true : false;
  }
  private grid[] getNeis(grid p) {
    final int[] adds = {-1, 0, 1, 0, -1};// 方向顺序为上右下左
    if (isOutOfBorder(p)) {
      return null;
    }
    grid[] ps = new grid[4];// 方向顺序为上右下左
    int 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 clearFence(int i, int j, int fx, int fy, Graphics g) {//清除并更新前面的节点
    int sx = padding + ((j > fy ? j : fy) * width),
        sy = padding + ((i > fx ? 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);
    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);

第六步:运行结果如下:
游戏提示:使用上下左右键控制小圆点的移动方向,直到找到出口赢得游戏。如果找不到出口,可按空格键使用系统生成的路径辅助找到出口。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201215145135890.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUzMDUyMDQ0,size_16,color_FFFFFF,t_70#pic_center)
系统生成的路径如下
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201226005132642.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUzMDUyMDQ0,size_16,color_FFFFFF,t_70#pic_center)
#### 总结
通过迷宫游戏的设计,对于我们培养基本程序设计素养的培养和软件格子者的工作作风有很多帮助,也使我们将理论与实践结合在一起。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值