生成雷场的原理java

编程入门 行业动态 更新时间:2024-10-19 02:20:18

生成雷场的<a href=https://www.elefans.com/category/jswz/34/1770123.html style=原理java"/>

生成雷场的原理java

本文介绍一个简单的扫雷游戏例子,屏幕抓图如下。

可执行的jar文件(j2sdk1.4.2_08编译打包,包括源代码):附件:jMine.jar(20K)『要解决的问题』1. 地雷,标识棋等图形的绘制;2. 游戏数据(地雷位置)的产生;3. 非地雷格子显示数字的计算;4. 游戏逻辑『包中源文件列表』 - hysun.minegame -- ConfigDialog.java -- FieldCell.java -- GameFrame.java -- GamePanel.java -- GraphicsUtil.javaConfigDialog(extends JDialog)是配置游戏数据(雷场行列数,地雷数目)的对话框,就不多说了。

GameFrame(extends JFrame)只是提供一个应用窗口,也不说了。

GraphicsUtil提供图形绘制方法。

FieldCell代表一个格子。

GamePanel(extends JComponent implements MouseListener)代表整个雷场,并且控制游戏逻辑。

『GraphicsUtil』

该类提供static方法,绘制游戏中各种图形,并且将格子大小设成32x32。详情如下表所列:

未知区域

[蓝色区域].... public static Color ukcolor = new Color(99, 130, 191); .... public static void drawUnknown(Graphics g, int x, int y) { g.setColor(ukcolor); g.fillRect(x, y, 32, 32); }

地雷.... public static Color mbcolor = new Color(90, 90, 90); .... public static void drawMine(Graphics g, int x, int y) { g.clearRect(x, y, 32, 32); g.setColor(mbcolor); g.fillOval(x+5, y+9, 21, 19); g.setColor(Color.black); g.fillRect(x+11, y+5, 10, 6); }

地雷标识旗

[小红旗].... public static void drawFlag(Graphics g, int x, int y) { g.clearRect(x, y, 32, 32); g.setColor(Color.red); g.fillRect(x+8, y+8, 16, 10); g.setColor(Color.black); g.drawLine(x+8, y+8, x+8, y+24); g.drawLine(x+9, y+8, x+9, y+24); }

非地雷格数字(0-8)

[不同数字使用不同颜色].... public static Color[] colorreg = new Color[] { null, // 0 Color.blue, // 1 Color.green.darker(), // 2 Color.red, // 3 Color.blue.darker(), // 4 Color.MAGENTA, // 5 Color.CYAN.darker(), // 6 Color.BLACK, // 7 Color.orange.darker() // 8 }; .... public static Font numfont = new Font("Verdana", Font.BOLD, 18); .... public static void drawNumber(Graphics g, int x, int y, int i) { g.clearRect(x, y, 32, 32); if (i == 0) return; g.setColor(colorreg[i]); g.setFont(numfont); FontMetrics fm = g.getFontMetrics(); String s = String.valueOf(i); int sx = (32 - fm.stringWidth(s)) / 2; int sy = (32 - fm.getHeight()) / 2 + fm.getAscent(); g.drawString(s, x+sx, y+sy); }

疑问标识旗

[小蓝旗,带问号].... public static Font qnmfont = new Font("Verdana", Font.PLAIN, 10); .... public static void drawDoubt(Graphics g, int x, int y) { g.clearRect(x, y, 32, 32); g.setColor(colorreg[4]); g.fillRect(x+8, y+8, 16, 10); g.setColor(Color.black); g.drawLine(x+8, y+8, x+8, y+24); g.drawLine(x+9, y+8, x+9, y+24); g.setColor(Color.yellow); g.setFont(qnmfont); FontMetrics fm = g.getFontMetrics(); String s = "?"; int sx = (14 - fm.stringWidth(s)) / 2; int sy = (10 - fm.getHeight()) / 2 + fm.getAscent(); g.drawString(s, x+sx+10, y+sy+8); }

叉叉

[game over时标柱错误的判断].... public static void drawCross(Graphics g, int x, int y) { g.setColor(Color.black); g.drawLine(x+2, y+2, x+28, y+28); g.drawLine(x+2, y+3, x+28, y+29); g.drawLine(x+3, y+2, x+29, y+28); g.drawLine(x+2, y+28, x+28, y+2); g.drawLine(x+2, y+27, x+28, y+1); g.drawLine(x+3, y+28, x+29, y+2); }好了,问题1圆满解决。

『FieldCell』

该类的关键在于格子相关的属性变量,如下表所列:

变量详情

int state代表该格子目前所处状态,取值范围是该类所定义的几个常数:UNKNOWN(该格子目前还是未知区域), FLAGGED(已经被标识为地雷), DOUBTED(被怀疑为地雷), REVEALED(已经被挖开), WRONG_F(game over时错误标识为地雷), WRONG_D(game over时错误怀疑为地雷)

boolean isMine顾名思义,表明该格子是否埋有地雷

int number只有当该格子没有地雷时,该变量才被用到,标识该格子周围的地雷数目,数目0-8

int gHintGraphics Hint,UI利用该信息为该格子画出适当的图形,每当格子状态改变时,gHint的值将根据以上三个变量做出相应的调整。gHint的数值和实际图形的映射可以参看源代码的注释。

该类对上述变量进行操作(get/set)的方法除外,还有一个方法public void draw(Graphics g, int x, int y)。此方法根据gHint的值利用GraphicsUtil提供的方法对自身的格子进行绘画,会被GamePanel调用到。

『GamePanel』

最后看看游戏的老大吧

。该类中有一些游戏状态显示的代码,主要是根JLabel,JButton等相关的,就略去不提了。

------

GamePanel里面有一个2D的数组:FieldCell[][] cells。问题2和3是关于游戏前数据的初始化问题,其代码包含在public void setGameParam(int mineNum, int r, int c)方法里面。

地雷数据产生的原理很简单,不断随机产生0到总格子数之间的一个数,只到不重复的数目达到所需地雷数目。如下:.... int totalNum = r * c; cells = new FieldCell[r][c]; for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { cells[i][j] = new FieldCell(); } } int count = 0; while (count < mineNum) { int s = (int) (Math.random() * totalNum); FieldCell fc = cells[s/c][s%c]; if (!fc.isMine()) { fc.setMine(true); count++; } }

相邻地雷数目的计算就要一个格子一个格子的过一边了。原理也很简单,每个格子有8个相邻的格子(处于边界的格子除外),每个格子都检查一下是不是地雷。如下:.... for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (!cells[i][j].isMine()) { int num = 0; if (i-1 >= 0) { if (j-1 >= 0 && cells[i-1][j-1].isMine()) num++; if (cells[i-1][j].isMine()) num++; if (j+1 < c && cells[i-1][j+1].isMine()) num++; } { // i if (j-1 >= 0 && cells[i][j-1].isMine()) num++; if (cells[i][j].isMine()) num++; if (j+1 < c && cells[i][j+1].isMine()) num++; } if (i+1 < r) { // i+1 if (j-1 >= 0 && cells[i+1][j-1].isMine()) num++; if (cells[i+1][j].isMine()) num++; if (j+1 < c && cells[i+1][j+1].isMine()) num++; } cells[i][j].setNumber(num); } // end Non-Mine cell if } // end for on j } // end for on i

至此,问题2,3也得到解决。另外需要提到的是GamePanel是一个JComponent的子类,它的图形是通过override下面这个方法实现的:.... protected void paintComponent(Graphics g) { g.setColor(Color.lightGray); g.fillRect(0, 0, w, h); for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { //格子大小是32×32,这里用34就在每两个格子间留下2的空隙 cells[i][j].draw(g, j*34, i*34); } } }

代码中的w, h为该面板的长,宽,根据格子数目设置(每两个格子中间留有一段空隙)。上面讲到FieldCell类的draw方法就是在这里被调用的。

------

游戏逻辑的解决是由对鼠标事件的处理完成的。GamePanel实现了MouseListener这个接口,不过这里只用到了mouseClicked这个方法。由于实际代码中牵涉到很多其他更新用户界面的方法,为求简练,这里将用pseudo code来解释:public void mouseClicked(MouseEvent e) { 根据鼠标事件记录的位置找出相应的格子; if (该格子已经被挖开: FieldCell.REVEALED) return; if (左键点击) { if (被插了小红旗) //这是用来防止玩家误操作的 return; if (踩到地雷了) { game over; //鼠标事件停止响应 显示所有未挖出地雷,并且用叉叉标出错误的红旗和蓝旗; } else { //挖地雷,标柱蓝旗的格子可以挖开 调用一个叫reveal(int i, int j)方法。 // reveal(int int) 是个递归的方法,首先将自己挖开, // 然后如果自己是个数字为0的格子,对相邻的8个格子调用reveal方法。 // reveal(int int)每挖开一个格子,挖开格子计数加加。 查看是否满足胜利条件(被挖开格子数+被插小红旗的格子数=总格子数); if (胜利) 恭喜玩家,停止鼠标事件响应; } } else if (右键点击) { //右键用来控制插旗子 if (格子状态==FieldCell.UNKNOWN) { if (插的小红旗数目 < 总地雷数) { 给格子插上红旗(设置状态); 红旗计数加加; 查看是否胜利(同上); } else { //sorry, 你的红旗用完了,改用蓝旗吧。 给格子插上蓝旗(设置状态); } } else if (格子状态==FieldCell.FLAGGED) { //红旗飘扬 拔掉红旗,换成蓝旗; 红旗计数减减; } else if (格子状态==FieldCell.DOUBTED) { //蓝旗招摇 回归未知区域; } } 调用repaint()将雷场重画一边;//这个很关键,不然游戏对于玩家的操作将“无动于衷”。 }

好了,问题4也解决了,大功告成!

更多推荐

生成雷场的原理java

本文发布于:2024-02-05 08:22:18,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1673762.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:原理   java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!