如何使用Java實現掃雷小遊戲
效果展示
主類別:GameWin類別
package com.sxt; import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class GameWin extends JFrame { int width = 2 * GameUtil.OFFSET + GameUtil.MAP_W * GameUtil.SQUARE_LENGTH; int height = 4 * GameUtil.OFFSET + GameUtil.MAP_H * GameUtil.SQUARE_LENGTH; Image offScreenImage = null; MapBottom mapBottom = new MapBottom(); MapTop mapTop = new MapTop(); void launch(){ GameUtil.START_TIME=System.currentTimeMillis(); this.setVisible(true); this.setSize(width,height); this.setLocationRelativeTo(null); this.setTitle("Java扫雷小游戏"); this.setDefaultCloseOperation(EXIT_ON_CLOSE); //鼠标事件 this.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); switch (GameUtil.state){ case 0 : if(e.getButton()==1){ GameUtil.MOUSE_X = e.getX(); GameUtil.MOUSE_Y = e.getY(); GameUtil.LEFT = true; } if(e.getButton()==3) { GameUtil.MOUSE_X = e.getX(); GameUtil.MOUSE_Y = e.getY(); GameUtil.RIGHT = true; } //去掉break,任何时候都监听鼠标事件 case 1 : case 2 : if(e.getButton()==1){ if(e.getX()>GameUtil.OFFSET + GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2) && e.getX()<GameUtil.OFFSET + GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W/2) + GameUtil.SQUARE_LENGTH && e.getY()>GameUtil.OFFSET && e.getY()<GameUtil.OFFSET+GameUtil.SQUARE_LENGTH){ mapBottom.reGame(); mapTop.reGame(); GameUtil.FLAG_NUM=0; GameUtil.START_TIME=System.currentTimeMillis(); GameUtil.state=0; } } break; default: } } }); while (true){ repaint(); try { Thread.sleep(40); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void paint(Graphics g) { offScreenImage = this.createImage(width,height); Graphics gImage = offScreenImage.getGraphics(); //设置背景颜色 gImage.setColor(Color.lightGray); gImage.fillRect(0,0,width,height); mapBottom.paintSelf(gImage); mapTop.paintSelf(gImage); g.drawImage(offScreenImage,0,0,null); } public static void main(String[] args) { GameWin gameWin = new GameWin(); gameWin.launch(); } }
底層地圖MapBottom類別
//底层地图:绘制游戏相关组件 package com.sxt; import java.awt.*; public class MapBottom { BottomRay bottomRay = new BottomRay(); BottomNum bottomNum = new BottomNum(); { bottomRay.newRay(); bottomNum.newNum(); } //重置游戏 void reGame(){ for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { GameUtil.DATA_BOTTOM[i][j]=0; } } bottomRay.newRay(); bottomNum.newNum(); } //绘制方法 void paintSelf(Graphics g){ g.setColor(Color.BLACK); //画竖线 for (int i = 0; i <= GameUtil.MAP_W; i++) { g.drawLine(GameUtil.OFFSET + i * GameUtil.SQUARE_LENGTH, 3*GameUtil.OFFSET, GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH, 3*GameUtil.OFFSET+GameUtil.MAP_H*GameUtil.SQUARE_LENGTH); } //画横线 for (int i = 0; i <=GameUtil.MAP_H; i++){ g.drawLine(GameUtil.OFFSET, 3*GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH, GameUtil.OFFSET+GameUtil.MAP_W*GameUtil.SQUARE_LENGTH, 3*GameUtil.OFFSET+i*GameUtil.SQUARE_LENGTH); } for (int i = 1; i <= GameUtil.MAP_W ; i++) { for (int j = 1; j <= GameUtil.MAP_H; j++) { //雷 if (GameUtil.DATA_BOTTOM[i][j] == -1) { g.drawImage(GameUtil.lei, GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.SQUARE_LENGTH - 2, GameUtil.SQUARE_LENGTH - 2, null); } //数字 if (GameUtil.DATA_BOTTOM[i][j] >=0) { g.drawImage(GameUtil.images[GameUtil.DATA_BOTTOM[i][j]], GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 15, GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 5, null); } } } //绘制数字,剩余雷数,倒计时 GameUtil.drawWord(g,""+(GameUtil.RAY_MAX-GameUtil.FLAG_NUM), GameUtil.OFFSET, 2*GameUtil.OFFSET,30,Color.red); GameUtil.drawWord(g,""+(GameUtil.END_TIME-GameUtil.START_TIME)/1000, GameUtil.OFFSET + GameUtil.SQUARE_LENGTH*(GameUtil.MAP_W-1), 2*GameUtil.OFFSET,30,Color.red); switch (GameUtil.state){ case 0: GameUtil.END_TIME=System.currentTimeMillis(); g.drawImage(GameUtil.face, GameUtil.OFFSET + GameUtil.SQUARE_LENGTH * (GameUtil.MAP_W/2), GameUtil.OFFSET, null); break; case 1: g.drawImage(GameUtil.win, GameUtil.OFFSET + GameUtil.SQUARE_LENGTH * (GameUtil.MAP_W/2), GameUtil.OFFSET, null); break; case 2: g.drawImage(GameUtil.over, GameUtil.OFFSET + GameUtil.SQUARE_LENGTH * (GameUtil.MAP_W/2), GameUtil.OFFSET, null); break; default: } } }
頂層地圖MapTop類別
顶层地图类:绘制顶层组件 package com.sxt; import java.awt.*; public class MapTop { //格子位置 int temp_x; int temp_y; //重置游戏 void reGame(){ for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { GameUtil.DATA_TOP[i][j]=0; } } } //判断逻辑 void logic(){ temp_x=0; temp_y=0; if(GameUtil.MOUSE_X>GameUtil.OFFSET && GameUtil.MOUSE_Y>3*GameUtil.OFFSET){ temp_x = (GameUtil.MOUSE_X - GameUtil.OFFSET)/GameUtil.SQUARE_LENGTH+1; temp_y = (GameUtil.MOUSE_Y - GameUtil.OFFSET * 3)/GameUtil.SQUARE_LENGTH+1; } if(temp_x>=1 && temp_x<=GameUtil.MAP_W && temp_y>=1 && temp_y<=GameUtil.MAP_H){ if(GameUtil.LEFT){ //覆盖,则翻开 if(GameUtil.DATA_TOP[temp_x][temp_y]==0){ GameUtil.DATA_TOP[temp_x][temp_y]=-1; } spaceOpen(temp_x,temp_y); GameUtil.LEFT=false; } if(GameUtil.RIGHT){ //覆盖则插旗 if(GameUtil.DATA_TOP[temp_x][temp_y]==0){ GameUtil.DATA_TOP[temp_x][temp_y]=1; GameUtil.FLAG_NUM++; } //插旗则取消 else if(GameUtil.DATA_TOP[temp_x][temp_y]==1){ GameUtil.DATA_TOP[temp_x][temp_y]=0; GameUtil.FLAG_NUM--; } else if(GameUtil.DATA_TOP[temp_x][temp_y]==-1){ numOpen(temp_x,temp_y); } GameUtil.RIGHT=false; } } boom(); victory(); } //数字翻开 void numOpen(int x,int y){ //记录旗数 int count=0; if(GameUtil.DATA_BOTTOM[x][y]>0){ for (int i = x-1; i <=x+1 ; i++) { for (int j = y-1; j <=y+1 ; j++) { if(GameUtil.DATA_TOP[i][j]==1){ count++; } } } if(count==GameUtil.DATA_BOTTOM[x][y]){ for (int i = x-1; i <=x+1 ; i++) { for (int j = y-1; j <=y+1 ; j++) { if(GameUtil.DATA_TOP[i][j]!=1){ GameUtil.DATA_TOP[i][j]=-1; } //必须在雷区当中 if(i>=1&&j>=1&&i<=GameUtil.MAP_W&&j<=GameUtil.MAP_H){ spaceOpen(i,j); } } } } } } //失败判定 t 表示失败 f 未失败 boolean boom(){ if(GameUtil.FLAG_NUM==GameUtil.RAY_MAX){ for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { if(GameUtil.DATA_TOP[i][j]==0){ GameUtil.DATA_TOP[i][j]=-1; } } } } for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { if(GameUtil.DATA_BOTTOM[i][j]==-1&&GameUtil.DATA_TOP[i][j]==-1){ GameUtil.state = 2; seeBoom(); return true; } } } return false; } //失败显示 void seeBoom(){ for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { //底层是雷,顶层不是旗,显示 if(GameUtil.DATA_BOTTOM[i][j]==-1&&GameUtil.DATA_TOP[i][j]!=1){ GameUtil.DATA_TOP[i][j]=-1; } //底层不是雷,顶层是旗,显示差错旗 if(GameUtil.DATA_BOTTOM[i][j]!=-1&&GameUtil.DATA_TOP[i][j]==1){ GameUtil.DATA_TOP[i][j]=2; } } } } //胜利判断 t 表示胜利 f 未胜利 boolean victory(){ //统计未打开格子数 int count=0; for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { if(GameUtil.DATA_TOP[i][j]!=-1){ count++; } } } if(count==GameUtil.RAY_MAX){ GameUtil.state=1; for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { //未翻开,变成旗 if(GameUtil.DATA_TOP[i][j]==0){ GameUtil.DATA_TOP[i][j]=1; } } } return true; } return false; } //打开空格 void spaceOpen(int x,int y){ if(GameUtil.DATA_BOTTOM[x][y]==0){ for (int i = x-1; i <=x+1 ; i++) { for (int j = y-1; j <=y+1 ; j++) { //覆盖,才递归 if(GameUtil.DATA_TOP[i][j]!=-1){ if(GameUtil.DATA_TOP[i][j]==1){GameUtil.FLAG_NUM--;} GameUtil.DATA_TOP[i][j]=-1; //必须在雷区当中 if(i>=1&&j>=1&&i<=GameUtil.MAP_W&&j<=GameUtil.MAP_H){ spaceOpen(i,j); } } } } } } //绘制方法 void paintSelf(Graphics g){ logic(); for (int i = 1; i <= GameUtil.MAP_W ; i++) { for (int j = 1; j <= GameUtil.MAP_H; j++) { //覆盖 if (GameUtil.DATA_TOP[i][j] == 0) { g.drawImage(GameUtil.top, GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.SQUARE_LENGTH - 2, GameUtil.SQUARE_LENGTH - 2, null); } //插旗 if (GameUtil.DATA_TOP[i][j] == 1) { g.drawImage(GameUtil.flag, GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.SQUARE_LENGTH - 2, GameUtil.SQUARE_LENGTH - 2, null); } //差错旗 if (GameUtil.DATA_TOP[i][j] == 2) { g.drawImage(GameUtil.noflag, GameUtil.OFFSET + (i - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.OFFSET * 3 + (j - 1) * GameUtil.SQUARE_LENGTH + 1, GameUtil.SQUARE_LENGTH - 2, GameUtil.SQUARE_LENGTH - 2, null); } } } } }
底層數字BottomNum類別
//底层数字类 package com.sxt; public class BottomNum { void newNum() { for (int i = 1; i <=GameUtil.MAP_W ; i++) { for (int j = 1; j <=GameUtil.MAP_H ; j++) { if(GameUtil.DATA_BOTTOM[i][j]==-1){ for (int k = i-1; k <=i+1 ; k++) { for (int l = j-1; l <=j+1 ; l++) { if(GameUtil.DATA_BOTTOM[k][l]>=0){ GameUtil.DATA_BOTTOM[k][l]++; } } } } } } } }
初始化地雷BottomRay類別
//初始化地雷类 package com.sxt; public class BottomRay { //存放坐标 int[] rays = new int[GameUtil.RAY_MAX*2]; //地雷坐标 int x,y; //是否放置 T 表示可以放置 F 不可放置 boolean isPlace = true; //生成雷 void newRay() { for (int i = 0; i < GameUtil.RAY_MAX*2 ; i=i+2) { x= (int) (Math.random()*GameUtil.MAP_W +1);//1-12 y= (int) (Math.random()*GameUtil.MAP_H +1);//1-12 //判断坐标是否存在 for (int j = 0; j < i ; j=j+2) { if(x==rays[j] && y==rays[j+1]){ i=i-2; isPlace = false; break; } } //将坐标放入数组 if(isPlace){ rays[i]=x; rays[i+1]=y; } isPlace = true; } for (int i = 0; i < GameUtil.RAY_MAX*2; i=i+2) { GameUtil.DATA_BOTTOM[rays[i]][rays[i+1]]=-1; } } }
工具GameUtil類別
//工具类:存放静态参数,工具方法 package com.sxt; import java.awt.*; public class GameUtil { //地雷个数 static int RAY_MAX = 5; //地图的宽 static int MAP_W = 11; //地图的高 static int MAP_H = 11; //雷区偏移量 static int OFFSET = 45; //格子边长 static int SQUARE_LENGTH = 50; //插旗数量 static int FLAG_NUM = 0; //鼠标相关 //坐标 static int MOUSE_X; static int MOUSE_Y; //状态 static boolean LEFT = false; static boolean RIGHT = false; //游戏状态 0 表示游戏中 1 胜利 2 失败 static int state = 0; //倒计时 static long START_TIME; static long END_TIME; //底层元素 -1 雷 0 空 1-8 表示对应数字 static int[][] DATA_BOTTOM = new int[MAP_W+2][MAP_H+2]; //顶层元素 -1 无覆盖 0 覆盖 1 插旗 2 差错旗 static int[][] DATA_TOP = new int[MAP_W+2][MAP_H+2]; //载入图片 static Image lei = Toolkit.getDefaultToolkit().getImage("imgs/lei.png"); static Image top = Toolkit.getDefaultToolkit().getImage("imgs/top.gif"); static Image flag = Toolkit.getDefaultToolkit().getImage("imgs/flag.gif"); static Image noflag = Toolkit.getDefaultToolkit().getImage("imgs/noflag.png"); static Image face = Toolkit.getDefaultToolkit().getImage("imgs/face.png"); static Image over = Toolkit.getDefaultToolkit().getImage("imgs/over.png"); static Image win = Toolkit.getDefaultToolkit().getImage("imgs/win.png"); static Image[] images = new Image[9]; static { for (int i = 1; i <=8 ; i++) { images[i] = Toolkit.getDefaultToolkit().getImage("imgs/num/"+i+".png"); } } static void drawWord(Graphics g,String str,int x,int y,int size,Color color){ g.setColor(color); g.setFont(new Font("仿宋",Font.BOLD,size)); g.drawString(str,x,y); } }
總結
#在使用Java掃雷小遊戲時遇到了許多問題,在解決問題時,確實對java的物件導向程式設計有了更深入的理解。雖然GUI現在並沒有很大的市場,甚至好多初學者已經放棄了學習GUI,但是利用GUI程式設計的流程對於培養程式設計興趣,深入理解Java程式設計有很大的作用。
本程式共封裝了五個類,分別是主類GameWin類,繪製底層地圖和繪製頂層地圖的類MapBottom類和MapTop類,繪製底層數字的類BottomNum類,以及初始化地雷的BottomRay類和工具GameUtil類,用於儲存靜態參數和方法。
遊戲的設計類似windows掃雷,使用者在圖形化使用者介面內利用滑鼠監聽事件標記雷區,左上角表示剩餘雷的數量,右上角動態顯示使用的時間。使用者可選擇中間組件按鈕重新遊戲。
為了解決程式視窗閃爍的問題,本程式採用了雙緩衝技術。
程式的整體介面佈局:
專案結構:
#程式測試:
以上是如何使用Java實現掃雷小遊戲的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP適用於Web開發和內容管理系統,Python適合數據科學、機器學習和自動化腳本。 1.PHP在構建快速、可擴展的網站和應用程序方面表現出色,常用於WordPress等CMS。 2.Python在數據科學和機器學習領域表現卓越,擁有豐富的庫如NumPy和TensorFlow。
