实验三 迷宫游戏

开始界面

设置一个难度等级不同的地图

  1. 这里就想放置几个按钮,每个不同按钮进去就是不同的地图大小,大小是一样的,就是格子数不一样。
      private ImageIcon mouse = new ImageIcon("");
        private JButton button1 = new JButton("24 X 24", mouse);
        private JButton button2 = new JButton("35 X 35", mouse);
        private JButton button3 = new JButton("46 X 46", mouse);
        private JButton button4 = new JButton("?", mouse);
     
  2. 按钮是要放在面板之上的,所以有ADD去添加一下,然后在对按钮设置监听
  3. 提示信息就是在面板上加一下文字做一下解释说明
  4. 主界面的布局,基本设置就是面板的标题,大小,面板出现位置,面板关闭设置,还有一些属性
  5. 其次就是设计一下按下每个按钮之后会发生的事情
  6. 限制一下按下问号按钮时用户输入情况的设置

这个类的代码

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

@SuppressWarnings("serial")
public class StartUI extends JFrame implements ActionListener {

    private ImageIcon mouse = new ImageIcon("");
    private JButton button1 = new JButton("24 X 24", mouse);
    private JButton button2 = new JButton("35 X 35", mouse);
    private JButton button3 = new JButton("46 X 46", mouse);
    private JButton button4 = new JButton("?", mouse);


    StartUI() {

        //将选择按钮包含在选择面板上
        JPanel choose = new JPanel();
        choose.setLayout(new GridLayout(2, 2));
        choose.add(button1);
        choose.add(button2);
        choose.add(button3);
        choose.add(button4);

        //注册侦听器
        button1.addActionListener(this);
        button2.addActionListener(this);
        button3.addActionListener(this);
        button4.addActionListener(this);

        //提示信息
        JPanel message = new JPanel() {   //匿名内部类
            protected void paintComponent(Graphics g) {
                setSize(200, 300);
                g.drawString("请选择场地大小", 100, 35);
            }
        };

        //主界面布局
        setLayout(new BorderLayout(120, 40));
        add(choose, BorderLayout.CENTER);
        add(message, BorderLayout.NORTH);
        add(new JPanel(), BorderLayout.EAST);
        add(new JPanel(), BorderLayout.WEST);
        add(new JPanel(), BorderLayout.SOUTH);

        //基本设置
        setTitle("迷宫游戏");
        setSize(800, 600);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        setResizable(false);
    }

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

    //按钮事件处理
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == button1) {
            dispose(); // setVisible(false);
            new map(18, 18);
        } else if (e.getSource() == button2) {
            dispose();  //setVisible(false);
            new map(25, 25);
        } else if (e.getSource() == button3) {
            dispose();  //setVisible(false);
            new map(40, 40);
        } else {
            getData();
        }
    }

    public void getData() {
        int m = 0, n = 0;
        String crowString;
        try {
            crowString = JOptionPane.showInputDialog("请输入自定义的行数(>5)");
            m = Integer.parseInt(crowString);
            crowString = JOptionPane.showInputDialog("请输入自定义的列数(>5)");
            n = Integer.parseInt(crowString);
            if (m <= 5 || n <= 5) throw new Exception();
            else {
                dispose();  //setVisible(false);
                new map(m, n);
            }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, 
                    "由于用户取消或输入不符合要求等原因,未正常创建迷宫。", 
                    "未创建迷宫!", JOptionPane.ERROR_MESSAGE);
        }

    }

}

设计一下游戏的地图界面

  1. 先设置一下菜单项,把菜单中的按钮添加到控制面板上。
  2. 生成迷宫地图。
  3. 生成随机路径。
  4. 实现鼠标对各个按钮的监听。
  5. 实现一下键盘上下左右的监听。
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.RandomAccessFile;

import javax.swing.*;

@SuppressWarnings("serial")
public class map extends JFrame implements ActionListener, KeyListener, Runnable {
    static int m, n;
    static wrmPane[][] tp = null;        //显示动画,同一包内类均可访问

    //时间限制
    static Thread timeThread;                //时间控制线程
    static int timelimit, remaintime;
    static JPanel timePanel = new JPanel() {     //剩余时间显示面板
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            String rt;
            if (timelimit == 0) {
                rt = "无限制";
                setForeground(Color.GREEN);    //青色表示无时间限制
            } else {
                rt = remaintime / 3600 + " : " + (remaintime - (remaintime / 3600) * 3600) / 60 + " : " + remaintime % 60;
                if (remaintime > 10)
                    setForeground(Color.BLUE);      //剩余时间充足时为绿色
                else
                    setForeground(Color.RED);      //剩余时间很少时为红色
            }
            g.drawString("剩余时间:  " + rt, 220, 16);
        }
    };

    // 菜单项
    private JMenuItem m_start = new JMenuItem("开始新游戏(S)");
    private JMenuItem m_time = new JMenuItem("游戏时间限制(L)");
    private JMenuItem m_return = new JMenuItem("返回主界面(R)");
    private JMenuItem m_exit = new JMenuItem("退出游戏(Q)");
    private JMenuItem m_savefile = new JMenuItem("保存迷宫结构(W)");
    private JMenuItem m_importfile = new JMenuItem("导入迷宫结构(I)");
    private JMenuItem m_selfconfig = new JMenuItem("编辑当前迷宫(E)");
    private JMenuItem m_randommake = new JMenuItem("随机生成迷宫(Z)");
    private JMenuItem m_sortpath = new JMenuItem("显示最短路径(T)");
    private JMenuItem m_DFSpath = new JMenuItem("随意显示一个路径(K)");
    //private JMenuItem m_help = new JMenuItem("游戏使用说明(H)");
   // private JMenuItem m_about = new JMenuItem("关于迷宫游戏(A)");


    @SuppressWarnings("deprecation")
    map(int x, int y) {
        m = x;
        n = y;
        tp = new wrmPane[m][n];
        timelimit = remaintime = 0;                //初始化时,时间为0,代表没有时间限制

        timeThread = new Thread(this);
        timeThread.start();
        timeThread.suspend();

        //菜单
        JMenu game = new JMenu("游戏");
        JMenu file = new JMenu("文件");
        JMenu edit = new JMenu("编辑");
        JMenu tip = new JMenu("提示");
        //JMenu help = new JMenu("帮助");
        game.add(m_start);
        game.add(m_time);
        game.add(m_return);
        game.add(m_exit);
        file.add(m_savefile);
        file.add(m_importfile);
        edit.add(m_selfconfig);
        edit.add(m_randommake);
        tip.add(m_sortpath);
        tip.add(m_DFSpath);
        //help.add(m_help);
        //help.add(m_about);

        //菜单栏
        JMenuBar menu = new JMenuBar();
        menu.add(game);
        menu.add(file);
        menu.add(edit);
        menu.add(tip);
        //menu.add(help);

        //初始化迷宫组件,并生成随机路径
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++) {
                tp[i][j] = new wrmPane();
            }
        Operations.creatMaze();  //深度优先遍历生成至少有一条随机通道的迷宫

        //迷宫地图
        JPanel mazePane = new JPanel();
        mazePane.setLayout(new GridLayout(m, n, 0, 0));
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                mazePane.add(tp[i][j]);
            }
        }

        //菜单和时间显示放在同一面板上
        JPanel northPanel = new JPanel();
        northPanel.setLayout(new GridLayout(1, 1));
        northPanel.add(menu);
        northPanel.add(timePanel);
        timePanel.setBackground(new Color(245, 240, 245));
        menu.setBackground(new Color(245, 240, 245));

        //添加到框架
        setLayout(new BorderLayout());
        add(northPanel, BorderLayout.NORTH);
        add(mazePane, BorderLayout.CENTER);
        add(new JPanel(), BorderLayout.SOUTH);

        //注册监听器
        m_start.addActionListener(this);
        m_time.addActionListener(this);
        m_return.addActionListener(this);
        m_exit.addActionListener(this);
        m_savefile.addActionListener(this);
        m_importfile.addActionListener(this);
        m_selfconfig.addActionListener(this);
        m_randommake.addActionListener(this);
        m_sortpath.addActionListener(this);
        m_DFSpath.addActionListener(this);
        //m_help.addActionListener(this);
        //m_about.addActionListener(this);
        addKeyListener(this);

        //基本设置
        setTitle("迷宫游戏");
        setSize(850, 650);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        setResizable(false);

    }

    map() {
        this(25, 25);
    }

    //导入迷宫结构
    @SuppressWarnings("deprecation")
    public void importFile() {
        map.timeThread.suspend();    //时间控制线程休眠
        JFileChooser jfile = new JFileChooser();  //文件选择器
        jfile.setFileSelectionMode(JFileChooser.FILES_ONLY);            //文件选择器选择模式
        jfile.showOpenDialog(null);               //打开文件
        File file = jfile.getSelectedFile();       //选择文件
        try {
            String f = file.getAbsolutePath();
            RandomAccessFile in = new RandomAccessFile(f, "rw");
            int newm = in.readInt(), newn = in.readInt();
            if (newm != m || newn != n) {
                dispose();
                new map(newm, newn);
            }
            int flag;
            for (int i = 0; i < m; i++)
                for (int j = 0; j < n; j++) {
                    flag = in.readInt();
                    if (flag == 2) {
                        Operations.m_startx = i;
                        Operations.m_starty = j;
                        Operations.m_currex = i;
                        Operations.m_currey = j;
                    }
                    tp[i][j].change(flag);
                }
            in.close();
            repaint();
            int anwser = JOptionPane.showConfirmDialog(null,
                    "文件中的迷宫结构已导入成功,是否开始游戏?",
                    "文件导入成功!", JOptionPane.YES_NO_CANCEL_OPTION);
            if (anwser == JOptionPane.YES_OPTION) Operations.start();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null,
                    "导入迷宫结构失败,可能是用户取消或文件不存在、文件数据有误等原因造成的。",
                    "错误提示", JOptionPane.ERROR_MESSAGE);
        }
        Operations.changeable_key = false;      //不可用键盘移动老鼠
        Operations.restart = false;               //保证开始游戏时使用的是导入的的迷宫
    }

    //重写run方法,进行时间控制
    public void run() {
        if (timelimit > 0) {
            while (true) {
                try {
                    Thread.sleep(1000);
                    if (remaintime > 0)
                        remaintime--;
                    timePanel.repaint();
                    if (timelimit > 0 && remaintime == 0) {
                        if (Operations.m_currex != m - 1 || Operations.m_currey != n - 1) {
                            Object[] options = {"新游戏", "重来一次"};
                            int response = JOptionPane.showOptionDialog(this,
                                    "  很遗憾,你没有在限制的时间里完成任务\n请选择开始新的游戏,或重玩此游戏",
                                    "游戏超时!", JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE,
                                    null, options, options[0]);
                            if (response == 0) {
                                Operations.restart = true;
                                Operations.start();
                            } else {
                                remaintime = timelimit;
                                tp[Operations.m_currex][Operations.m_currey].change(1);
                                Operations.m_currex = Operations.m_startx;
                                Operations.m_currey = Operations.m_starty;
                                tp[Operations.m_currex][Operations.m_currey].change(2);
                            }

                        }
                    }
                } catch (Exception e) {
                }
            }
        }
    }


    //菜单事件处理
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == m_start) {
            Operations.start();
        } else if (e.getSource() == m_return) {
            dispose(); //关闭当前窗口
            new StartUI();
        } else if (e.getSource() == m_DFSpath) {
            Operations.findPath();
        } else if (e.getSource() == m_exit) {
            System.exit(0);
        } else if (e.getSource() == m_selfconfig) {
            Operations.selfconfig();
        } else if (e.getSource() == m_randommake) {
            Operations.randommake();
        } //else if (e.getSource() == m_help) {
          //  Operations.showHelp();
        //}
        else if (e.getSource() == m_sortpath) {
            Operations.sortestPath();
        } //else if (e.getSource() == m_about) {
            //Operations.about();
        //}
        else if (e.getSource() == m_savefile) {
            Operations.saveFile();
        } else if (e.getSource() == m_importfile) {
            importFile();
        } else if (e.getSource() == m_time) {
            Operations.setTime();
        }

    }

    //键盘事件处理
    public void keyTyped(KeyEvent e) {
    }

    public void keyReleased(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_DOWN:
                Operations.down();
                break;
            case KeyEvent.VK_UP:
                Operations.up();
                break;
            case KeyEvent.VK_LEFT:
                Operations.left();
                break;
            case KeyEvent.VK_RIGHT:
                Operations.right();
                break;
            case KeyEvent.VK_S:
                Operations.start();
                break;
            case KeyEvent.VK_Q:
                System.exit(0);
                break;
            case KeyEvent.VK_R:
                dispose();
                new StartUI();
                break;
            case KeyEvent.VK_E:
                Operations.selfconfig();
                break;
            case KeyEvent.VK_Z:
                Operations.randommake();
                break;
            case KeyEvent.VK_K:
                Operations.findPath();
                break;
            //case KeyEvent.VK_H:
                //Operations.showHelp();
                //break;
            case KeyEvent.VK_T:
                Operations.sortestPath();
                break;
            //case KeyEvent.VK_A:
                //Operations.about();
               // break;
            case KeyEvent.VK_W:
                Operations.saveFile();
                break;
            case KeyEvent.VK_I:
                importFile();
                break;
            case KeyEvent.VK_L:
                Operations.setTime();
                break;
        }

    }

}

对于墙和路之间的设计

  1. 对墙和路之间做一个区分
  2. 对路径深度图初始化
  3. 动态更新路径深度图
  4. 利用已经生成的路径深度图,找到最短路径
  5. 深度优先搜素
  6. 对监听的按钮进行设计
  7. 生成随机迷宫

  1. import java.io.*;
    
    import javax.swing.JFileChooser;
    import javax.swing.JOptionPane;
    
    public class Operations {
        //数据同一包内类均可访问
        static int m, n;   //用于拷贝map.m和map.n的值
        static int m_currex, m_currey;   //当前位置
        static int m_startx, m_starty;   //开始位置
        static boolean changeable_key = false;     //是否可用键盘控制移动
        static boolean restart = false;
    
        private static boolean[] isBeVisit = null;//DFS生成随机迷宫专用数据
    
        //***************迷宫最短路径深度图算法
        @SuppressWarnings("deprecation")
        public static void sortestPath() {
    
            map.timeThread.suspend();    //时间控制线程休眠
            changeable_key = false;   //不可用键盘控制
            setEditable(false);       //不可编辑
    
            m = map.m;
            n = map.n;
            int max = m * n;                 //任意一点到目的地的最短路径长度不会超出m*n。
            int[] depthGraph = new int[m * n];     //路径深度图
    
            //路径深度图初始化
            depthGraph[m * n - 1] = 0;                //目的地到自己的距离自然是0
            for (int i = 0; i < m * n - 1; i++) {
                if (map.tp[i / n][i % n].isWall())
                    depthGraph[i] = -1;           //墙表示为-1,表示无通路
                else
                    depthGraph[i] = max;           //未确定距离时已max表示
            }
    
    
            boolean flag = true;             //循环过程中是否有某点的路径深度被修改
            int currex, currey;               //记录当前访问点的坐标
            int aroundmin;                   //周围可行方向的 最小路径深度 + 1
    
            //动态更新路径深度图直至其达到稳态(即最后一次循环过程中不再有路径深度被修改)
            while (flag) {
                flag = false;
                for (int s = m * n - 1; s >= 0; s--) {
                    if (depthGraph[s] != -1) {
                        aroundmin = depthGraph[s];
                        currex = s / n;
                        currey = s % n;
                        if (currey + 1 < n && depthGraph[s + 1] != -1 && depthGraph[s + 1] + 1 < aroundmin)
                            aroundmin = depthGraph[s + 1] + 1;
                        if (currex + 1 < m && depthGraph[s + n] != -1 && depthGraph[s + n] + 1 < aroundmin)
                            aroundmin = depthGraph[s + n] + 1;
                        if (currey - 1 >= 0 && depthGraph[s - 1] != -1 && depthGraph[s - 1] + 1 < aroundmin)
                            aroundmin = depthGraph[s - 1] + 1;
                        if (currex - 1 >= 0 && depthGraph[s - n] != -1 && depthGraph[s - n] + 1 < aroundmin)
                            aroundmin = depthGraph[s - n] + 1;
                        if (aroundmin < depthGraph[s]) {
                            depthGraph[s] = aroundmin;
                            flag = true;
                        }
    
                    }
                }
            }
    
            //利用已生成的路径深度图,找到从海绵宝宝到派大星之间的最短路径
            int[] path = new int[m * n];                    //用于存放最短路径的数组
            int currePoint = m_startx * n + m_starty;         //当前访问点,初始值为老鼠位置
            int depth = depthGraph[currePoint];         //海绵宝宝位置的路径深度值
            int step = depth - 1;                     //当前要查找的路径深度
            while (step > 0) {
                currex = currePoint / n;
                currey = currePoint % n;
                if (currey + 1 < n && depthGraph[currePoint + 1] == step) {
                    currePoint += 1;
                } else if (currex + 1 < m && depthGraph[currePoint + n] == step) {
                    currePoint += n;
                } else if (currey - 1 >= 0 && depthGraph[currePoint - 1] == step) {
                    currePoint -= 1;
                } else if (currex - 1 >= 0 && depthGraph[currePoint - n] == step) {
                    currePoint -= n;
                }
                path[step--] = currePoint;
            }
            int s;         //临时存放位置
            for (int i = 1; i < depth; i++) {
                s = path[i];
                map.tp[s / n][s % n].change(2);   //显示最短路径
            }
    
            restart = true;                //可开始新游戏
    
        }
    
    
        //****************回溯法查找路径(深度优先搜索)
        @SuppressWarnings("deprecation")
        public static void findPath() {
            map.timeThread.suspend();    //时间控制线程休眠
    
            changeable_key = false;   //不可用键盘控制海绵宝宝
            setEditable(false);       //不可编辑
    
            m = map.m;
            n = map.n;
            int currex = m_startx, currey = m_starty;
            int direction = 0;
            int distance;
            int[] point = new int[m * n];
            boolean[] isBeVisit = new boolean[m * n];
            for (int i = 0; i < m * n - 1; i++) isBeVisit[i] = false;
            int step = 0;
            point[step] = currex * n + currey;
            step++;
            for (; ; ) {
                if (currex == m - 1 && currey == n - 1) {      //已找到派大星
                    for (int i = 1; i < step - 1; i++)         //step-1对应目的地,不再重画。
                        map.tp[point[i] / n][point[i] % n].change(2);
                    restart = true;                //可开始新游戏
                    return;
                }
                switch (direction) {       //按右0下1左2上3的优先顺序遍历
                    case 0:
                        if (currey + 1 < n && !map.tp[currex][currey + 1].isWall() && !isBeVisit[currex * n + currey + 1]) {
                            point[step] = currex * n + currey + 1;
                            isBeVisit[currex * n + currey + 1] = true;
                            currey++;
                            step++;
                            direction = 0;
    
                        } else direction++;
                        break;
                    case 1:
                        if (currex + 1 < m && !map.tp[currex + 1][currey].isWall() && !isBeVisit[(currex + 1) * n + currey]) {
                            point[step] = (currex + 1) * n + currey;
                            isBeVisit[(currex + 1) * n + currey] = true;
                            currex++;
                            step++;
                            direction = 0;
    
                        } else direction++;
                        break;
                    case 2:
                        if (currey - 1 >= 0 && !map.tp[currex][currey - 1].isWall() && !isBeVisit[currex * n + currey - 1]) {
                            point[step] = currex * n + currey - 1;
                            isBeVisit[currex * n + currey - 1] = true;
                            currey--;
                            step++;
                            direction = 0;
                        } else direction++;
                        break;
                    case 3:
                        if (currex - 1 >= 0 && !map.tp[currex - 1][currey].isWall() && !isBeVisit[(currex - 1) * n + currey]) {
                            point[step] = (currex - 1) * n + currey;
                            isBeVisit[(currex - 1) * n + currey] = true;
                            currex--;
                            step++;
                            direction = 0;
                        } else direction++;
                        break;
                    default:              //此路不通,后退一步查看下一方向
                        step--;
                        isBeVisit[point[step]] = false;
                        if (step <= 0) {
                            JOptionPane.showMessageDialog(null,
                                    "抱歉,该迷宫没有通路,请使用其它迷宫开始新的游戏。",
                                    "该迷宫没有通路!", JOptionPane.ERROR_MESSAGE);
                            restart = true;
                            return;
                        }
    
                        distance = point[step] - point[step - 1];
                        if (distance == 1) {        //在上一步的右方向(0),则返回上一步时 再找下一个方向 direction=1   下同
                            currex = point[step - 1] / n;
                            currey = point[step - 1] % n;
                            direction = 1;
                        } else if (distance == n) {
                            currex = point[step - 1] / n;
                            currey = point[step - 1] % n;
                            direction = 2;
                        } else if (distance == -1) {
                            currex = point[step - 1] / n;
                            currey = point[step - 1] % n;
                            direction = 3;
                        } else {
                            direction = 4;       //继续后退
                        }
                }
            }
        }
    
    
        //深度优先遍历生成至少有一条随机通道的迷宫
        public static void creatMaze() {
            m = map.m;
            n = map.n;
            //遍历前初始化工作
            isBeVisit = new boolean[m * n];
            for (int i = 0; i < m * n; i++) isBeVisit[i] = false;      //是否已被访问
    
            //迷宫初始化
            for (int i = 0; i < m; i++) {                  //防止发生两边上全为墙的情况
                map.tp[i][0].change(Math.random() * 3 > 1 ? 0 : 1);
                map.tp[i][n - 1].change(Math.random() * 3 > 1 ? 0 : 1);
            }
            for (int i = 0; i < n; i++) {
                map.tp[0][i].change(Math.random() * 3 > 1 ? 0 : 1);
                map.tp[m - 1][i].change(Math.random() * 3 > 1 ? 0 : 1);
            }
            for (int i = 1; i < m - 1; i++)
                for (int j = 1; j < n - 1; j++)
                    map.tp[i][j].change(0);  //内部的位置初始化全为墙
    
            m_startx = (int) (Math.random() * m / 2);
            m_starty = (int) (Math.random() * n / 2);    //随机生成海绵宝宝位置
    
            //******************从老鼠位置开始深度优先遍历与它x 、y坐标相差均为偶数的点构成的图
            DFS(m_startx * n + m_starty);
    
            //*******************     这一步在 tp[m-2][n-2]与海绵宝宝位置x 、y坐标相差均为偶数时非常重要,保证有到达粮仓的路径
            if (Math.random() * 2 > 1)
                map.tp[m - 2][n - 1].change(1);
            else
                map.tp[m - 1][n - 2].change(1);    //两者只要有一个为路即可,故随机取其一
    
            //海绵宝宝和派大星的位置作另作处理
            map.tp[m_startx][m_starty].change(2);  //海绵宝宝
            map.tp[m - 1][n - 1].change(3);            //派大星
    
            changeable_key = false;  //键盘不可控制海绵宝宝移动
            m_currex = m_startx;
            m_currey = m_starty;  //开始新游戏前老鼠当前位置与开始位置相等
            restart = false;
        }
    
        //****************从S点开始深度优先遍历与它x 、y坐标相差均为偶数的点构成的图,并打通每一步需要通过的墙
        public static void DFS(int s) {
            map.tp[s / n][s % n].change(1);
            isBeVisit[s] = true;
    
            int[] direction = new int[4];              //用于以随机顺序存储方向   右0下1左2上3
            boolean[] isStored = new boolean[4];
            for (int i = 0; i < 4; i++) isStored[i] = false;    //方向是否已被存储
            int currex = s / n, currey = s % n;                 //当前点对应的实际坐标
    
            //按随机顺序存储方向
            int rand, length = 0;      //随机数 用于产生随机顺序 ,length表示已存储方向的个数
            while (length < 4) {
                rand = (int) (Math.random() * 4);    //0~3
                if (!isStored[rand]) {
                    direction[length++] = rand;
                    isStored[rand] = true;            //修改为true,防止重复存储
                }
            }
            for (int i = 0; i < 4; i++) {
                switch (direction[i]) {
                    case 0:
                        if (currey + 2 < n) {                             //右
                            if (!isBeVisit[s + 2]) {
                                map.tp[currex][currey + 1].change(1); //打通[currex][currey]与[currex][currey+2]之间的墙,下同
                                DFS(s + 2);
                            }
                        }
                        break;
                    case 1:
                        if (currex + 2 < m) {                              //下
                            if (!isBeVisit[s + 2 * n]) {
                                map.tp[currex + 1][currey].change(1);
                                DFS(s + 2 * n);
                            }
                        }
                        break;
                    case 2:                                               //左
                        if (currey - 2 >= 0) {
                            if (!isBeVisit[s - 2]) {
                                map.tp[currex][currey - 1].change(1);
                                DFS(s - 2);
                            }
                        }
                        break;
                    case 3:                                            //上
                        if (currex - 2 >= 0) {
                            if (!isBeVisit[s - 2 * n]) {
                                map.tp[currex - 1][currey].change(1);
                                DFS(s - 2 * n);
                            }
                        }
                        break;
                }
            }
        }
    
        //开始游戏
        @SuppressWarnings("deprecation")
        public static void start() {
            if (restart) creatMaze();
            map.remaintime = map.timelimit;
            map.timeThread.resume();
            changeable_key = true;    //可用键盘控制老鼠
            setEditable(false);       //不可编辑
        }
    
        //设置时间
        @SuppressWarnings("deprecation")
        public static void setTime() {
            int time;
            String timeStr;
            try {
                timeStr = JOptionPane.showInputDialog("请输入最大时间限制(单位为秒):\n提示:输入0代表无时间限制)");
                time = Integer.parseInt(timeStr);
                if (time < 0) throw new Exception();
                map.timelimit = time;   //设置完时间后重新开始游戏
                Object[] options = {"新游戏", "当前游戏"};
                int response = JOptionPane.showOptionDialog(null, "请选择是否开始新游戏还是重新玩当前游戏", "游戏时间设置成功", JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
                if (response == 0) {
                    restart = true;
                    start();
                } else if (response == 1) {
                    map.tp[m_currex][m_currey].change(1);
                    m_currex = m_startx;
                    m_currey = m_starty;
                    map.tp[m_currex][m_currey].change(2);
                    restart = false;
                    start();
                }
            } catch (Exception e) {
                JOptionPane.showMessageDialog(null, "由于用户取消或输入不符合要求等原因,游戏时间限定设置失败。", "未更改游戏时间限制", JOptionPane.ERROR_MESSAGE);
                map.timeThread.resume(); //返回调用前状态
            }
    
        }
    
    
        //保存迷宫文件
    
        /*************************************************************
         *代码重写   2015/06/29
         *        由于之前的代码没考虑提示路径的情况下,整个老鼠经过的路都将被保留为老鼠,
         *    这样下次打开文件就会没法玩了,所以重新修改代码,仅保留初始位置的老鼠。
         *************************************************************/
        @SuppressWarnings("deprecation")
        public static void saveFile() {
            map.timeThread.suspend();    //时间控制线程休眠
            JFileChooser jfile = new JFileChooser();  //文件选择器
            jfile.setFileSelectionMode(0);            //文件选择器选择模式
            jfile.showSaveDialog(null);               //保存文件
            File file = jfile.getSelectedFile();       //选择文件
    
            if (file.exists()) {
                int anwser = JOptionPane.showConfirmDialog(null, "文件已存在,是否覆盖保存?", "文件已存在", JOptionPane.YES_NO_CANCEL_OPTION);
                if (anwser != JOptionPane.YES_OPTION) return;
            }
    
            try {
                String f = file.getAbsolutePath();                  //文件名
                RandomAccessFile out = new RandomAccessFile(f, "rw");
                out.writeInt(m);
                out.writeInt(n);
                for (int i = 0; i < m; i++) {
                    for (int j = 0; j < n; j++) {
                        if (i == m_startx && j == m_starty)       //仅保留初始位置的老鼠
                            out.writeInt(2);
                        else if (map.tp[i][j].getFlag() == 2)     //其他位置老鼠保存为路
                            out.writeInt(1);
                        else
                            out.writeInt(map.tp[i][j].getFlag());
                    }
                }
                out.close();
            } catch (Exception e) {
                JOptionPane.showMessageDialog(null, "未能保存文件,可能是用户取消或文件路径有误!", "错误提示", JOptionPane.ERROR_MESSAGE);
            } finally {
                map.timeThread.resume(); //时间控制仍是调用保存函数之前的状态
            }
        }
    
        //海绵宝宝的移动  只有往右走和往下走才有可能到派大星,因此只检测这两种情况是否成功
        public static void down() {
            if (!changeable_key) return;
            if (m_currex == m - 1 && m_currey == n - 1) return;
            if (m_currex + 1 == m - 1 && m_currey == n - 1) {
                map.tp[m_currex][m_currey].change(1);
                m_currex++;
                restart = true;
                int anwser = JOptionPane.showConfirmDialog(null, "恭喜成功找到派大星,是否开始新的游戏。", "成功!", JOptionPane.YES_NO_CANCEL_OPTION);
                if (anwser == JOptionPane.YES_OPTION) start();
            } else if (m_currex + 1 < m && !map.tp[m_currex + 1][m_currey].isWall()) {
                map.tp[m_currex][m_currey].change(1);
                map.tp[++m_currex][m_currey].change(2);
            }
        }
    
        public static void up() {
            if (!changeable_key) return;
            if (m_currex == m - 1 && m_currey == n - 1) return;
            if (m_currex - 1 >= 0 && !map.tp[m_currex - 1][m_currey].isWall()) {
                map.tp[m_currex][m_currey].change(1);
                map.tp[--m_currex][m_currey].change(2);
            }
        }
    
        public static void left() {
            if (!changeable_key) return;
            if (m_currex == m - 1 && m_currey == n - 1) return;
            if (m_currey - 1 >= 0 && !map.tp[m_currex][m_currey - 1].isWall()) {
                map.tp[m_currex][m_currey].change(1);
                map.tp[m_currex][--m_currey].change(2);
            }
        }
    
        public static void right() {
            if (!changeable_key) return;
            if (m_currex == m - 1 && m_currey == n - 1) return;
            if (m_currex == m - 1 && m_currey + 1 == n - 1) {
                map.tp[m_currex][m_currey].change(1);
                m_currey++;
                restart = true;
                int anwser = JOptionPane.showConfirmDialog(null, "恭喜你帮助海绵宝宝成功找到派大星,是否开始新的游戏。", "成功!", JOptionPane.YES_NO_CANCEL_OPTION);
                if (anwser == JOptionPane.YES_OPTION) start();
            } else if (m_currey + 1 >= 0 && !map.tp[m_currex][m_currey + 1].isWall()) {
                map.tp[m_currex][m_currey].change(1);
                map.tp[m_currex][++m_currey].change(2);
            }
        }
    
    
        //设置是否能编辑
        public static void setEditable(boolean e) {
            for (int i = 0; i < m; i++)
                for (int j = 0; j < n; j++)
                    map.tp[i][j].setChangeable_click(e);
            //即使在编辑模式下老鼠和粮仓也不能修改
            map.tp[m - 1][n - 1].setChangeable_click(false);
            map.tp[m_startx][m_starty].setChangeable_click(false);
        }
    
        //自定义迷宫
        @SuppressWarnings("deprecation")
        public static void selfconfig() {
            map.timeThread.suspend();    //时间控制线程休眠
            changeable_key = false;      //不可用键盘移动海绵宝宝
            setEditable(true);           //可以使墙变路、路变墙
            m_startx = m_currex;
            m_startx = m_currex;
            restart = false;               //保证开始游戏时使用的是编辑得到的迷宫
            map.timeThread.resume();   //时间控制回到调用函数前状态
        }
    
        //随机迷宫
        @SuppressWarnings("deprecation")
        public static void randommake() {
            map.timeThread.suspend();    //时间控制线程休眠
            creatMaze();
            changeable_key = false;
            setEditable(true);
            restart = false;        //保证开始游戏时使用的是编辑得到的迷宫
            map.timeThread.resume();   //时间控制回到调用函数前状态
        }
    
        //帮助文档
        /*
        @SuppressWarnings("deprecation")
        public static void showHelp() {
            map.timeThread.suspend();    //时间控制线程休眠
            String help = "本迷宫游戏非常简单,相信您很快就能知道它所有的功能,以下仅作出一些简\n单的说明:\n"
                    + "一、程序启动时的主界面给出3种不同的游戏场地大小供用户选择,用户也可通\n      过点击?按钮来自定义场地大小。\n"
                    + "二、进入游戏界面后,游戏所有操作选项都在菜单栏里,为方便您的使用,每个\n     选项快捷键都配有相应的快捷键。\n"
                    + "三、开始游戏后,可用方向健控制老鼠的移动。\n"
                    + "四、在编辑模式下,可以点击某一块区域使其变为墙或路。\n"
                    + "五、除非开始游戏,在其它任何状态下均不可移动老鼠;同样除编辑模式外,其\n     它状态亦不可随意更改墙和路。\n"
                    + "六、本程序以二进制文件方式读取和存储迷宫结构,因此,保存和打开文件时最好\n    选用.dat后缀名。\n"
                    + "七、在此,十分感谢您的使用!";
            JOptionPane.showMessageDialog(null, help.toString(), "游戏使用说明", JOptionPane.INFORMATION_MESSAGE);
            map.timeThread.resume();    //时间控制回到调用函数前状态
        }
    
        //关于作者
        @SuppressWarnings("deprecation")
        public static void about() {
            map.timeThread.suspend();    //时间控制线程休眠
            String me = "   江苏科技大学计算机学院      \n\n"
                    + "        物联网工程专业          \n\n"
                    + "            2019级2班                 \n\n"
                    + "              何苗苗                  \n\n";
            JOptionPane.showMessageDialog(null, me, "作者信息", JOptionPane.INFORMATION_MESSAGE);
            map.timeThread.resume();   //时间控制回到调用函数前状态
        }
    
         */
    
    }
    

    这个类主要是对地图中的图片进行设计

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class wrmPane extends JPanel implements MouseListener {
        private boolean changeable_click;
        private int flag;  //标志 0:墙 1:路 2:海绵宝宝 3:派大星
        private Image wall = new ImageIcon("F:\\图片\\墙.jpg").getImage();        //墙
        private Image road = new ImageIcon("F:\\图片\\海底.jpg").getImage();        //路
        private Image mouse = new ImageIcon("F:\\图片\\海绵宝宝.jpg").getImage();      //海绵宝宝
        private Image liangc = new ImageIcon("F:\\图片\\派大星.jpg").getImage();   //派大星
    
        wrmPane(int f) {
            flag = f;
            changeable_click = false;    //初始化时不能通过鼠标点击改变 flag 的值
            addMouseListener(this);
        }
    
        wrmPane() {
            this(0);
        }
    
        //重写paintComponent方法,画图
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (flag == 0)
                g.drawImage(wall, 0, 0, getWidth(), getHeight(), this);
            else if (flag == 1)
                g.drawImage(road, 0, 0, getWidth(), getHeight(), this);
            else if (flag == 2)
                g.drawImage(mouse, 0, 0, getWidth(), getHeight(), this);
            else
                g.drawImage(liangc, 0, 0, getWidth(), getHeight(), this);
        }
    
        //访问器
        public int getFlag() {
            return flag;
        }
    
        //是否为墙
        public boolean isWall() {
            return flag == 0;
        }
    
        //是否可通过点击实现墙路互变
        public boolean isChangeable() {
            return changeable_click;
        }
    
        //设置为是否能墙路互变
        public void setChangeable_click(boolean c) {
            changeable_click = c;
        }
    
        //修改标志并重画面板
        public void change(int f) {
            flag = f;
            repaint();
        }
    
        //鼠标事件处理
        public void mouseEntered(MouseEvent e) {
        }
    
        public void mouseExited(MouseEvent e) {
        }
    
        public void mousePressed(MouseEvent e) {
        }
    
        public void mouseReleased(MouseEvent e) {
        }
    
        public void mouseClicked(MouseEvent e) {
            if (!changeable_click) return;
            if (flag == 0) {
                flag = 1;
                repaint();
            } else {
                flag = 0;
                repaint();
            }
        }
    
    }
    

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值