用Java實(shí)現(xiàn)連連看小游戲
很多人寫(xiě)游戲都是從連連看或者五子棋這類的簡(jiǎn)單小游戲入手的,最近我也嘗試著寫(xiě)了一個(gè)連連看,想要再梳理一遍其中的思路。
連連看的規(guī)則
連連看要求在一定范圍內(nèi)找到兩個(gè)特征一樣并且能夠通過(guò)空白的通道在兩折(直角)以內(nèi)相連的東西,連續(xù)點(diǎn)擊兩個(gè)東西之后消除。
通常我們會(huì)選擇用圖片來(lái)進(jìn)行匹配,這樣更直觀有趣。
如何存儲(chǔ)連連看的數(shù)據(jù)
使用二維數(shù)組進(jìn)行存儲(chǔ),每一個(gè)數(shù)組元素對(duì)應(yīng)一個(gè)位置上的圖片種類。
例如我們分別用1,2,3,4代表四個(gè)不同的圖片,用0代表沒(méi)有圖片;那么二維數(shù)組{{},{},{},{}}就相應(yīng)地存儲(chǔ)對(duì)應(yīng)位置的數(shù)據(jù)。如果要對(duì)圖片進(jìn)行變更(連連看中的消除),那么只需要改變?cè)撐恢脤?duì)應(yīng)的數(shù)組元素的值就行了(在這個(gè)例子中,消除就改為0)。
如何實(shí)現(xiàn)數(shù)組數(shù)據(jù)的初始化
1、一般來(lái)說(shuō)連連看開(kāi)始都會(huì)隨機(jī)生成圖片,此處的隨機(jī)生成需要用到Random類里面的nextInt方法,能隨機(jī)生成給定范圍內(nèi)的隨機(jī)一個(gè)整數(shù)。
2、我們生成數(shù)組的時(shí)候要考慮一個(gè)問(wèn)題:連連看相同的圖片個(gè)數(shù)是偶數(shù),這樣才不會(huì)到最后形成落單的尷尬局面。
//隨機(jī)給出數(shù)組值,初始化游戲數(shù)據(jù) public int[][] DATA(int[][] data){ ?? ??? ??? ? ?? ??? ??? ?int[][] d=data; ?? ??? ??? ?Random random=new Random(); ?? ??? ??? ?for(int i=0;i<8;i++){ ?? ??? ??? ??? ?d[0][i]=0; ?? ??? ??? ??? ?d[7][i]=0; ?? ??? ??? ?} ?? ??? ??? ?for(int i=1;i<7;i++){ ?? ??? ??? ??? ?d[i][0]=0; ?? ??? ??? ??? ?d[i][7]=0; ?? ??? ??? ?} ?? ??? ??? ?for(int i=0;i<18;i++){ ?? ??? ??? ??? ? ?? ??? ??? ? ?? ??? ??? ??? ?int m=random.nextInt(Const.Const_TYPECOUNNT)+1; ?? ??? ??? ??? ?int x1=random.nextInt(Const.COL)+1; ?? ??? ??? ??? ?int y1=random.nextInt(Const.COL)+1; ?? ??? ??? ??? ? ?? ??? ??? ??? ?while(d[x1][y1]!=0){ ?? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ?x1=random.nextInt(Const.COL)+1; ?? ??? ??? ??? ??? ?y1=random.nextInt(Const.COL)+1; ?? ??? ??? ??? ?} ?? ??? ??? ??? ?d[x1][y1]=m;?? ? ?? ??? ??? ??? ?int x2=random.nextInt(Const.COL)+1; ?? ??? ??? ??? ?int y2=random.nextInt(Const.COL)+1; ?? ??? ??? ??? ?while(d[x2][y2]!=0){ ?? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ?x2=random.nextInt(Const.COL)+1; ?? ??? ??? ??? ??? ?y2=random.nextInt(Const.COL)+1; ?? ??? ??? ??? ? ?? ??? ??? ?} ?? ??? ??? ?d[x2][y2]=m; ?? ??? ??? ?} ?? ??? ??? ?return(d); ?? ??? ??? ? ?? ??? ?}
如何繪制圖片
連連看的存儲(chǔ)都是以int的類型存儲(chǔ)的,可我們要呈現(xiàn)出來(lái)的效果是一張一張的圖片……
先用Image導(dǎo)入所有圖片,最好圖片的命名能夠用數(shù)字命名,這樣就可以批量導(dǎo)入了。這里就不過(guò)多贅述了,看實(shí)例代碼吧:
?public void init(){ ?? ??? ?imgArr = new Image[Const.Const_TYPECOUNNT]; ?? ??? ?for(int i=0; i < imgArr.length; i++){ ?? ??? ?imgArr[i] = new ImageIcon("llkImage/"+i+".jpg").getImage(); ?? ??? ?} ?? ?}
關(guān)于圖片大小的調(diào)整我用的是比較原始的方法:編輯圖片本身像素大?。贿€可以通過(guò)drawImage來(lái)直接規(guī)定大小。
重繪棋子
沒(méi)有重繪的窗體在我們對(duì)其進(jìn)行拖動(dòng)或者最小化等改變的時(shí)候會(huì)變成空白的,重繪就是將窗體的paint方法重寫(xiě),這樣對(duì)窗體的任何操作都會(huì)將paint方法重新寫(xiě)一遍。也就是在屏幕上重新畫(huà)一遍。
我們的棋子都存在一個(gè)二維數(shù)組里面,那么我們就可以將棋子繪制的步驟放在重繪里面來(lái)實(shí)現(xiàn),那么棋子就跟窗體一樣,可以“一直存在”了,也可以根據(jù)數(shù)組的改變來(lái)改變。
代碼示例:
public void paint(Graphics g) { ?? ??? ?// 重繪paint方法 ?? ??? ?super.paint(g); ?? ??? ?// ?? ??? ?for (int i = 1; i < Const.COL+1; i++) { ?? ??? ??? ?for (int j = 1; j < Const.ROW+1; j++) {?? ??? ? ?? ??? ?if (data[i][j] == 0) { ?? ??? ??? ?g.setColor(new Color(69,175,198)); ?? ??? ??? ?g.fillRect(Const.START_X + i * Const.SIZE, Const.START_Y + j * Const.SIZE, Const.SIZE, Const.SIZE); ?? ??? ?}? ?? ??? ?else { ?? ??? ??? ?g.drawImage(imgArr[data[i][j]-1], Const.START_X + i * Const.SIZE, Const.START_Y + j * Const.SIZE, null); ?? ??? ??? ?? ?? ??? ??? ?} ?? ??? ?} ?? ?}
連連看的實(shí)現(xiàn)算法
兩個(gè)圖片消除的方法有三種:
1.直線連接
2.一折連接
3.二折連接
其中二折連接可以找一個(gè)點(diǎn)既與其中一個(gè)圖片一折連接又與另一個(gè)圖片直線連接;一折連接又可以找一個(gè)點(diǎn)與其中一個(gè)圖片直線連接又與另一個(gè)圖片直線連接。
所以綜上所述,只需要寫(xiě)出一個(gè)直線連接的判斷方法,我們所有的規(guī)則方法就都可以實(shí)現(xiàn)了。
數(shù)組的元素=0時(shí)代表這里的圖片為空,有路可走。
首先,兩個(gè)數(shù)組元素直線相連的前提是這兩個(gè)元素的橫坐標(biāo)或者縱坐標(biāo)相等且路徑上的數(shù)組元素全部為零。
代碼示例:
//0折點(diǎn)的方法 public boolean zero(int[][] data,int X1, int Y1,int X2,int Y2){ ?? ??? ?int max;? ?? ??? ?int min; ?? ? ?? ??? ?//x值相等 ?? ??? ?if(X1==X2){ ?? ??? ??? ?max=Y1 > Y2 ? Y1:Y2; ?? ??? ??? ?min=Y1 < Y2 ? Y1:Y2; ?? ??? ??? ?for(int i=min+1;i<max;i++){ ?? ??? ??? ??? ?if(data[X1][i]!=0){ ?? ??? ??? ??? ??? ?return false; ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ??? ?return true; ?? ??? ?} ?? ??? ?//y值相等 ?? ??? ?else if(Y1==Y2){ ?? ??? ??? ?max=X1 > X2 ? X1:X2; ?? ??? ??? ?min=X1 < X2 ? X1:X2; ?? ??? ??? ?for(int i=min+1;i<max;i++){ ?? ??? ??? ??? ?if(data[i][Y1]!=0){ ?? ??? ??? ??? ??? ?return false; ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?return true; ?? ??? ?} ?? ??? ?else return false; ?? ?} ?? ?//1折點(diǎn)的方法 ? ? public boolean one(int[][] data,int X1, int Y1,int X2,int Y2){ ? ? ?? ? ? ? ?? ?if((zero(data,X1,Y1,X1,Y2)&&zero(data,X1,Y2,X2,Y2)&&data[X1][Y2]==0)||(data[X2][Y1]==0&&zero(data,X1,Y1,X2,Y1)&&zero(data,X2,Y1,X2,Y2))){ ? ? ?? ??? ?return true; ? ? ?? ?} ? ? ?? ?return false; ? ? ?? ?} ? ?? ?? ?//2折點(diǎn)的方法 ?? ?public boolean two(int[][] data,int X1, int Y1,int X2,int Y2){? ?? ??? ?//向下尋找一個(gè)第一折點(diǎn) ?? ??? ?for(int i=X1+1;i<=Const.COL+1;i++){ ?? ??? ??? ?if(zero(data,X1,Y1,i,Y1)&&one(data,i,Y1,X2,Y2)){ ?? ??? ??? ??? ?return true; ?? ??? ??? ?} ?? ??? ?} ?? ??? ?//向上尋找一個(gè)第一折點(diǎn) ?? ??? ?for(int i=X1-1;i>=0;i--){ ?? ??? ??? ?if(zero(data,X1,Y1,i,Y1)&&one(data,i,Y1,X2,Y2)){ ?? ??? ??? ??? ?return true; ?? ??? ??? ?} ?? ??? ?} ?? ??? ?//向左 ?? ??? ?for(int i=Y1-1;i>=0;i--){ ?? ??? ??? ?if(zero(data,X1,Y1,X1,i)&&one(data,X1,i,X2,Y2)){ ?? ??? ??? ??? ?return true; ?? ??? ??? ?} ?? ??? ?} ?? ??? ?//向右 ?? ??? ?for(int i=Y1+1;i<=Const.ROW+1;i++){ ?? ??? ??? ?if(zero(data,X1,Y1,X1,i)&&one(data,X1,i,X2,Y2)){ ?? ??? ??? ??? ?return true; ?? ??? ??? ?} ?? ??? ?} ?? ??? ?return false; ?? ?}
如何獲取兩次鼠標(biāo)點(diǎn)擊的位置
廢話不多說(shuō),直接上代碼:
//鼠標(biāo)點(diǎn)擊松開(kāi)事件 public void mouseReleased(MouseEvent e) { ?? ??? ?int x,y; ?? ??? ?Rule rule = new Rule(); ?? ??? ?x = e.getX(); ?? ??? ?y = e.getY(); ?? ??? ? ?? ??? ?if(count%2==0){ ?? ??? ?X1 = (x - Const.START_X) / Const.SIZE; ?? ??? ?Y1 = (y - Const.START_Y) / Const.SIZE; ?? ??? ?count++; ?? ??? ?} ?? ??? ?else { ?? ??? ?X2 = (x - Const.START_X) / Const.SIZE; ?? ??? ?Y2 = (y - Const.START_Y) / Const.SIZE; ?? ??? ?count++; ?? ??? ?if (rule.judge(X1, Y1, X2, Y2, data)&& ?? ??? ??? ??? ?(rule.zero(data,X1,Y1,X2,Y2)||rule.one(data, X1, Y1, X2, Y2)||rule.two(data, X1, Y1, X2, Y2))){ ?? ??? ??? ?data[X1][Y1]=0;data[X2][Y2]=0; ?? ??? ?} ?? ??? ?} ?? ??? ? ?? ??? ?ui.repaint(); ?? ??? ? ?? ?}
成果展示
以上,我的游戲還是個(gè)很簡(jiǎn)單的模板,仍待完善,可以把界面做得更精美,還可以增加游戲難度的選擇以及時(shí)間和步數(shù)的規(guī)定,最后還可以加上游戲的輸贏判斷,希望能夠幫助到有需要的人。
相關(guān)文章
InputStreamReader和BufferedReader用法及實(shí)例講解
這篇文章主要介紹了InputStreamReader和BufferedReader用法及實(shí)例講解的相關(guān)資料,需要的朋友可以參考下2015-12-12Java 覆蓋equals時(shí)總要覆蓋hashcode
這篇文章主要介紹了Java 覆蓋equals時(shí)總要覆蓋hashcode的相關(guān)資料,這里附有實(shí)例代碼,具有參考價(jià)值,需要的朋友可以參考下2016-12-126種Java創(chuàng)建對(duì)象的方式總結(jié)
在Java中,創(chuàng)建對(duì)象可以使用多種方式,本文將詳細(xì)介紹以下六種創(chuàng)建對(duì)象的方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-04-04java數(shù)據(jù)結(jié)構(gòu)與算法之希爾排序詳解
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之希爾排序,結(jié)合實(shí)例形式分析了希爾排序的概念、原理、實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-05-05SpringBoot校園綜合管理系統(tǒng)實(shí)現(xiàn)流程分步講解
這篇文章主要介紹了SpringBoot+Vue實(shí)現(xiàn)校園綜合管理系統(tǒng)流程分步講解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-09-09解決springboot配置logback-spring.xml不起作用問(wèn)題
這篇文章主要介紹了解決springboot配置logback-spring.xml不起作用問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Java實(shí)現(xiàn)SM3加密和驗(yàn)證的示例代碼
在商用密碼體系中,SM3主要用于數(shù)字簽名及驗(yàn)證、消息認(rèn)證碼生成及驗(yàn)證、隨機(jī)數(shù)生成等,其算法公開(kāi),本文給大家詳細(xì)介紹了使用Java實(shí)現(xiàn)SM3加密和驗(yàn)證,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2023-12-12java實(shí)現(xiàn)飛機(jī)大戰(zhàn)小游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)飛機(jī)大戰(zhàn)小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06