开始界面
设置一个难度等级不同的地图
- 这里就想放置几个按钮,每个不同按钮进去就是不同的地图大小,大小是一样的,就是格子数不一样。
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);
- 按钮是要放在面板之上的,所以有ADD去添加一下,然后在对按钮设置监听
- 提示信息就是在面板上加一下文字做一下解释说明
- 主界面的布局,基本设置就是面板的标题,大小,面板出现位置,面板关闭设置,还有一些属性
- 其次就是设计一下按下每个按钮之后会发生的事情
- 限制一下按下问号按钮时用户输入情况的设置
这个类的代码
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);
}
}
}
设计一下游戏的地图界面
- 先设置一下菜单项,把菜单中的按钮添加到控制面板上。
- 生成迷宫地图。
- 生成随机路径。
- 实现鼠标对各个按钮的监听。
- 实现一下键盘上下左右的监听。
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;
}
}
}
对于墙和路之间的设计
- 对墙和路之间做一个区分
- 对路径深度图初始化
- 动态更新路径深度图
- 利用已经生成的路径深度图,找到最短路径
- 深度优先搜素
- 对监听的按钮进行设计
- 生成随机迷宫
-
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(); } } }