Java實現經典遊戲2048的示例代碼
前言
2014年Gabriele Cirulli利用周末的時間寫2048這個遊戲的程序,僅僅隻是好玩而已。他想用一種不同的視覺展現效果和更快速的動畫來創造屬於自己的遊戲版本。
遊戲是用java語言實現,采用瞭swing技術進行瞭界面化處理,設計思路用瞭面向對象思想。
主要需求
每次控制所有方塊向同一個方向運動,兩個相同數字的方塊撞在一起之後合並成為他們的和,每次操作之後會在空白的方格處隨機生成一個2或者4,最終得到一個“2048”的方塊就算勝利瞭。如果16個格子全部填滿並且相鄰的格子都不相同也就是無法移動的話,那麼遊戲就會結束。
主要設計
1、遊戲面板生成顯示
2、方塊設計
3、鍵盤監聽,方向鍵控制數字移動
4、數字移動邏輯算法處理
5、數字累加到2048,遊戲勝利
功能截圖
遊戲開始
移動效果
代碼實現
界面佈局類
public class Game2048View implements ActionListener{ Block[] blocks; //方塊 JPanel myJPanel; //主面板 JPanel jp1,jp2; //子面板 // int moveFlag; // 用於累計移動的次數 boolean numFlag; // 用於判斷是否還能加入新的數字 JLabel scroeValue; //顯示分數 public Game2048View(JFrame myJFrame){ blocks=new Block[16]; // moveFlag=0; numFlag=true; this.myJPanel=(JPanel)myJFrame.getContentPane();///獲取內容面板 setJp1(); myJPanel.add(jp1,BorderLayout.NORTH); setJp2(); myJPanel.add(jp2, BorderLayout.CENTER); myJFrame.addKeyListener(new Game2048Logic(this,myJFrame,blocks,numFlag,scroeValue)); } public void addc(JPanel jp1,Component component, GridBagConstraints gbc,int gridwidth,int gridheight, int weightx,int weighty,int gridx,int gridy) { //此方法用來添加控件到容器中 gbc.gridwidth=gridwidth; //該方法是設置組件水平所占用的格子數,如果為0,就說明該組件是該行的最後一個 gbc.gridheight=gridheight; //該方法是設置組件垂直所占用的格子數 gbc.weightx=weightx; //該方法設置組件水平的拉伸幅度,如果為0就說明不拉伸,不為0就隨著窗口增大進行拉伸,0到1之間 gbc.weighty=weighty; //該方法設置組件垂直的拉伸幅度,如果為0就說明不拉伸,不為0就隨著窗口增大進行拉伸,0到1之間 gbc.gridx=gridx; gbc.gridy=gridy; gbc.fill=GridBagConstraints.BOTH; jp1.add(component,gbc); } public void setJp1() { GridBagLayout gbLayout=new GridBagLayout(); jp1=new JPanel(gbLayout); JPanel Jtitle=new JPanel(); JLabel title=new JLabel("2048"); title.setFont(new Font("font", Font.PLAIN, 45));//類型、風格、大小 title.setHorizontalAlignment(JLabel.LEFT);//jLabel的文本左右對齊屬性設置方法,對齊方式 Jtitle.add(title); jp1.add(Jtitle); JPanel Jscroe=new JPanel(new GridLayout(2, 1));//new GridLayout(2, 1)為網格佈局樣式。其中的參數“2”“1”分別為網格的“行數”和“列數”。 JLabel scroe=new JLabel("Scroe"); scroe.setFont(new Font("font", Font.PLAIN, 16)); scroe.setHorizontalAlignment(JLabel.CENTER); scroeValue=new JLabel("0"); scroeValue.setFont(new Font("font", Font.PLAIN, 16)); scroeValue.setHorizontalAlignment(JLabel.CENTER); Jscroe.add(scroe); Jscroe.add(scroeValue); jp1.add(Jscroe); JPanel Jnoite=new JPanel(); JLabel noite=new JLabel("方向鍵移動數字累加至2048"); noite.setFont(new Font("font", Font.PLAIN, 14)); noite.setHorizontalAlignment(JLabel.LEFT); Jnoite.add(noite); jp1.add(Jnoite); JPanel JnewGame=new JPanel(); JButton newGame=new JButton("New Game"); newGame.setHorizontalAlignment(JButton.CENTER); newGame.addActionListener(this); JnewGame.add(newGame); jp1.add(JnewGame); GridBagConstraints gbc=new GridBagConstraints(); addc(jp1, Jtitle, gbc, 3, 2, 60, 60, 0, 0); addc(jp1, Jscroe, gbc, 0, 2, 40, 60, 3, 0); addc(jp1, Jnoite, gbc, 3, 1, 60, 40, 0, 2); addc(jp1, JnewGame, gbc, 0, 1, 40, 40, 3, 2); } public void setJp2() { addBlock(); initBlock(); initBlock(); } /** * 添加方塊 */ public void addBlock(){ jp2=new JPanel(); /* * setLayout是對當前組件設置為流式佈局.組件在窗體中從左到右依次排列 如果排到行的末尾 換行排列 * GridLayout(int rows, int cols, int hgap, int vgap) 創建具有指定行數和列數的網格佈局。 rows - 該 rows 具有表示任意行數的值 cols - 該 cols 具有表示任意列數的值 hgap - 水平間距 vgap - 垂直間距 */ jp2.setLayout(new GridLayout(4, 4, 5, 5)); for (int i = 0; i < blocks.length; i++) { blocks[i]=new Block(); blocks[i].setHorizontalAlignment(JLabel.CENTER);// 不透明的標簽 blocks[i].setOpaque(true);// 設置控件不透明 jp2.add(blocks[i]); } } /** * 初始化方塊 */ public void initBlock(){ while (numFlag) { int index=(int) (Math.random()*16); if (blocks[index].getText().trim().equals("")) { blocks[index].setValue("2"); break; } else { continue; } } } /** * 獲得第一個子面板的高度 */ public int getMyJPanelHeidth() { return jp1.getSize().height; } @Override public void actionPerformed(ActionEvent e) { // TODO 自動生成的方法存根 newGame(); } /** * 重新開始遊戲 */ public void newGame() { for (int i = 0; i < blocks.length; i++) { blocks[i].setValue(""); } numFlag=true; scroeValue.setText("0"); initBlock(); initBlock(); } }
業務邏輯類
public class Game2048Logic implements KeyListener{ Block[] blocks; boolean numFlag; // 用於判斷是否還能加入新的數字 JLabel scroeValue; //顯示分數 int blocksarr[]=new int[4]; //保存一行/列方塊中的數值 JFrame myJFrame; int scroe=0; Game2048View game2048View; //初始化鍵盤事件 public Game2048Logic(Game2048View game2048View, JFrame myJFrame, Block[] blocks,boolean numFlag,JLabel scroeValue) { // TODO 自動生成的構造函數存根 this.blocks=blocks; this.numFlag=numFlag; this.scroeValue=scroeValue; this.myJFrame=myJFrame; this.game2048View=game2048View; } //初始化按鈕事件 public Game2048Logic() { // TODO 自動生成的構造函數存根 } public boolean getnumFlag() { return numFlag; } @Override public void keyPressed(KeyEvent e) { // TODO 自動生成的方法存根 int[] blocksarr=getBlock(); switch (e.getKeyCode()) { case KeyEvent.VK_UP: colBlock("up"); hasEmptyBlock(); if (Arrays.equals(blocksarr, getBlock())) { } else { refershBlock(); } isGameFail("up"); break; case KeyEvent.VK_DOWN: colBlock("down"); hasEmptyBlock(); if (Arrays.equals(blocksarr, getBlock())) { } else { refershBlock(); } isGameFail("down"); break; case KeyEvent.VK_LEFT: rowBlock("left"); hasEmptyBlock(); if (Arrays.equals(blocksarr, getBlock())) { } else { refershBlock(); } isGameFail("left"); break; case KeyEvent.VK_RIGHT: rowBlock("right"); hasEmptyBlock(); if (Arrays.equals(blocksarr, getBlock())) { } else { refershBlock(); } isGameFail("right"); break; default: break; } scroeValue.setText(""+scroe); win(); } /** * 垂直方向方塊移動處理函數 */ public void colBlock(String direction){ int tmp1=0; int tmp2=0; int index=0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (blocks[tmp1].getText().trim().equals("")) { tmp1+=4; if (tmp1>=16) { break; } else { continue; } } else { blocksarr[index]=Integer.parseInt(blocks[tmp1].getText().trim()); index+=1; tmp1+=4; if (tmp1>=16 || index>=4) { break; } else { continue; } } } switch (direction) { case "up": blocksarr=handleBlocksarr(blocksarr); break; case "down": blocksarr=reverseArr(handleBlocksarr(reverseArr(blocksarr))); break; default: break; } for (int n = 0; n < blocksarr.length; n++) { if (blocksarr[n]==0) { blocks[tmp2].setText(""); blocks[tmp2].setBackground(Color.gray); } else { blocks[tmp2].setValue(blocksarr[n]+""); } tmp2+=4; } index=0; tmp1=i+1; tmp2=i+1; //清空數組blockarr for (int n = 0; n < blocksarr.length; n++) { blocksarr[n]=0; } } } /** * 水平方向方塊移動處理函數 */ public void rowBlock(String direction) { int tmp1=0; int tmp2=0; int index=0; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (blocks[tmp1].getText().trim().equals("")) { tmp1+=1; if (tmp1>=16) { break; } else { continue; } } else { blocksarr[index]=Integer.parseInt(blocks[tmp1].getText().trim()); index+=1; tmp1+=1; if (tmp1>=16 || index>=4) { break; } else { continue; } } } switch (direction) { case "left": blocksarr=handleBlocksarr(blocksarr); break; case "right": blocksarr=reverseArr(handleBlocksarr(reverseArr(blocksarr))); break; default: break; } for (int n = 0; n < blocksarr.length; n++) { if (blocksarr[n]==0) { blocks[tmp2].setText(""); blocks[tmp2].setBackground(Color.gray); } else { blocks[tmp2].setValue(blocksarr[n]+""); } tmp2+=1; } index=0; //清空數組blockarr for (int n = 0; n < blocksarr.length; n++) { blocksarr[n]=0; } } } /** * 處理並返回一個數組 */ public int[] handleBlocksarr(int[] blocksarr) { int index=0; int[] result=new int[4]; for (int i = 0; i < blocksarr.length; i++) { //排序 if (blocksarr[i]!=0) { result[index]=blocksarr[i]; index++; } } if (index==0 || index==1) { for (int i = index; i < result.length; i++) { result[i]=0; } } else { for (int i = 0; i < blocksarr.length; i++) { blocksarr[i]=0; } switch (index) { case 2: if (result[0]==result[1]) { blocksarr[0]=result[0]+result[1]; scroe+=result[0]*2; } else { blocksarr=result; } break; case 3: if (result[0]==result[1]) { blocksarr[0]=result[0]+result[1]; scroe+=result[0]*2; blocksarr[1]=result[2]; } else { if (result[1]==result[2]) { blocksarr[0]=result[0]; blocksarr[1]=result[1]+result[2]; scroe+=result[1]*2; } else { blocksarr=result; } } break; case 4: if (result[0]==result[1]) { blocksarr[0]=result[0]+result[1]; scroe+=result[0]*2; if (result[2]==result[3]) { blocksarr[1]=result[2]+result[3]; scroe+=result[2]*2; } else { blocksarr[1]=result[2]; blocksarr[2]=result[3]; } } else { if (result[1]==result[2]) { blocksarr[0]=result[0]; blocksarr[1]=result[1]+result[2]; scroe+=result[1]*2; blocksarr[2]=result[3]; } else { blocksarr[0]=result[0]; blocksarr[1]=result[1]; if (result[2]==result[3]) { blocksarr[2]=result[2]+result[3]; scroe+=result[2]*2; } else { blocksarr=result; } } } break; default: break; } result=blocksarr; } return result; } /** * 反轉數組eg:45000 --> 00054 */ public int[] reverseArr(int[] arr) { int[] tmp=new int[arr.length]; int index=arr.length-1; for (int i = 0; i < arr.length; i++) { tmp[index]=arr[i]; index--; } return tmp; } /** * 刷新方塊,添加新出現的2或4 */ public void refershBlock(){ if (numFlag==false) { } while (numFlag) { int index=(int) (Math.random()*16); if (blocks[index].getText().trim().equals("")) { if (Math.random()<0.8) { blocks[index].setValue("2"); } else { blocks[index].setValue("4"); } break; } else { continue; } } } /** * 判斷是否有空的方塊 */ public void hasEmptyBlock() { for (int i = 0; i < blocks.length; i++) { if (blocks[i].getText().trim().equals("")) { this.numFlag=true; break; } else { this.numFlag=false; } } } /** * 判斷遊戲是否失敗 */ public void isGameFail(String direction) { boolean result=true; //true代表失敗 false代表沒有失敗 int tmp=0; if (numFlag == false) { // 表示沒有空的方塊 switch (direction) { case "up": case "down": for (int i = 0; i < 4; i++) { tmp=i*4; for (int j = 0; j < 3; j++) { if (blocks[tmp].getText().trim().equals(blocks[tmp+1].getText().trim())) { result = false; //遊戲未失敗 break; } else { tmp++; } } if (result==false) { break; } } break; case "left": case "right": for (int i = 0; i < 4; i++) { for (int j = 0; j < 3; j++) { if (blocks[tmp].getText().trim().equals(blocks[tmp+4].getText().trim())) { result = false; //遊戲未失敗 break; } else { tmp+=4; if (tmp>=16) { break; } else { continue; } } } tmp=i+1; if (result==false) { break; } } break; default: break; } } else { result=false; } if (result==true) { JOptionPane.showMessageDialog( null , "Game Over",null , JOptionPane.ERROR_MESSAGE) ; game2048View.newGame(); } else { } } /** * 判斷遊戲是否成功,即成功累加至2048 */ public void win() { for (int i = 0; i < blocks.length; i++) { if (blocks[i].getText().trim().equals("2048")) { JOptionPane.showMessageDialog( null , "YOU ARE WIN",null , JOptionPane.ERROR_MESSAGE) ; game2048View.newGame(); break; } } } /** * 獲得全部方塊內容,用於對比 */ public int[] getBlock() { int[] blocksarr=new int[16]; for (int i = 0; i < blocks.length; i++) { if (blocks[i].getText().trim().equals("")) { blocksarr[i]=0; } else { blocksarr[i]=Integer.parseInt(blocks[i].getText().trim()); } } return blocksarr; } @Override public void keyReleased(KeyEvent e) { // TODO 自動生成的方法存根 } @Override public void keyTyped(KeyEvent e) { // TODO 自動生成的方法存根 } }
總結
通過此次的《2048遊戲》遊戲實現,讓我對swing的相關知識有瞭進一步的瞭解,對java這門語言也有瞭比以前更深刻的認識。
java的一些基本語法,比如數據類型、運算符、程序流程控制和數組等,理解更加透徹。java最核心的核心就是面向對象思想,對於這一個概念,終於悟到瞭一些。
以上就是Java實現經典遊戲2048的示例代碼的詳細內容,更多關於Java 2048遊戲的資料請關註WalkonNet其它相關文章!