Java版2048
功能要求:2048的基本界面,能夠實現2048的遊戲功能。
總思路:兩個類:Game和GameListener。
Game負責界面的實現和paint方法的重寫
GameListener負責實現鍵盤和鼠標事件的處理。移動方法,相加方法,輸贏判斷和隨機數的出現都要在鍵盤監聽的方法中實現。
實現分析:要實現2048遊戲,首先需要考慮2048都有些什麽?
界面實現:
2048的遊戲界面很簡單,就是一些方格和數字。要實現這樣的界面,我們可以考慮一下使用Java的繪圖功能。具體來說就是使用JFrame類提供的Graphics對象進行繪圖。2048界面由一個大的矩形背景和包含數字的許多小方塊組成。Graphics對象的繪制矩形的方法就能實現背景和小方格的繪制。小方格內的數字則可以使用graphics的drawString方法來繪制。只需要在繪制的時候註意一下顏色就好。界面實現要擁到的類主要是JFrame類。
基本界面實現代碼,不過是一些按鈕之類的,沒什麽好說的。
private void initUI() {
setTitle("2048");
setDefaultCloseOperation(3);
setSize(600, 700);
setLocationRelativeTo(null);
this.setLayout(null);
//添加分數
jl2 = new JLabel("分數:0");
jl2.setFont(new Font("黑體", Font.BOLD, 30));
jl2.setBounds( 20, 30, 200, 50);
this.add(jl2);
//添加開始按鈕
ImageIcon start=new ImageIcon("res/start.png");//開始遊戲圖標,隨意替換就好
startJB=new JButton(start);
startJB.setBounds(280, 40, 120, 30);
startJB.setFocusable(false);
startJB.setBorderPainted(false);//設置按鈕的邊框為空
startJB.setFocusPainted(false );
startJB.setContentAreaFilled(false);//設置按鈕的邊框內填充顏色
//添加退一步按鈕
ImageIcon back=new ImageIcon("res/backicon.png");//遊戲結束圖標,隨意替換就好
backJB=new JButton(back);
backJB.setBounds(430, 40, 120, 30);
backJB.setFocusable(false);
backJB.setBorderPainted(false);
backJB.setFocusPainted(false);
backJB.setContentAreaFilled(false);
this.add(startJB);
this.add(backJB);
setVisible(true);
GameListener gl = new GameListener(this, arry, jl2,startJB,backJB);
addKeyListener(gl);
startJB.addActionListener(gl);
backJB.addActionListener(gl);
}
方格和數字的繪制:
方格和數字的繪制同樣是使用JFrame的畫布對象的繪制矩形的方法實現。
public void buffPaint(Graphics g) {
Image image = createImage(600, 600);
Graphics g2 = image.getGraphics();
g2.setColor(Color.LIGHT_GRAY);
Graphics2D g2d = (Graphics2D) g2;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.fillRoundRect(0, 0, Draw2048.RD, Draw2048.RD, 20, 20);
g2.setColor(Color.GRAY);
for (int r = 0; r < arry.length; r++) {
for (int c = 0; c < arry[r].length; c++) {
g2.fillRect(20 + c * (Draw2048.D + Draw2048.space), 20 + r
* (Draw2048.D + Draw2048.space), Draw2048.D, Draw2048.D);
}
}
for (int r = 0; r < arry.length; r++) {
for (int c = 0; c < arry[r].length; c++) {
if (arry[r][c] != 0) {
g2.setColor(255, 250, 240);
g2.fillRect(20 + c * (Draw2048.D + Draw2048.space), 20 + r
* (Draw2048.D + Draw2048.space), Draw2048.D,
Draw2048.D);
g2.setColor(new Color(0, 191, 255));
g2.setFont(new Font("楷體", Font.BOLD, Draw2048.FSIZE));
g2.drawString(arry[r][c] + "", 50 + c
* (Draw2048.D + Draw2048.space), 90 + r
* (Draw2048.D + Draw2048.space));
}
}
}
g.drawImage(image, 50, 150, this);
}
Draw2048是一個接口,裏面定義了關於方格繪制的相關常量,D方格邊長,space方格間間隔。RD背景大矩形的邊長。使用接口的好處就是使得界面的更改(如改成5*5的格子)可以更加方便的實現,提高程序的擴展性。另外界面需要不斷的更新,所以要調用paint方法不斷的重繪。如果直接把這裏的繪制寫在paint方法中,不斷的重繪會使得界面一直在閃爍。這裏的解決方案就是使用圖片緩沖,先在圖片中繪制好,在把圖片一次性繪制出來,這樣就不會出現界面的閃爍問題了。
移動實現:
要想讓方格移動起來,可以考慮的方法就是使用畫板的重繪。方格內的數字則使用一個二維數組來保存。每次移動就讓數組的值發生變化就行,然後根據數組的值把數據繪制到界面上。當然玩遊戲時總不能靠意念操控,我們需要有輸入設備,也就是鍵盤。所以需要給界面加上鍵盤監聽。當用戶按下不同的鍵則實現不同的移動算法。值得註意的是,在監聽類中編寫相應的移動算法的時候要理清循環的使用和結束(尤其是break語句的使用),否則會出現各種各樣的bug。移動實現是需要用到keyListener類。
下面是向上移動的實現,其他方向的移動都差不多,自己琢磨一下就好:
//向上移動的算法
for (int r = 0; r < arry.length; r++)
for (int c = 0; c < arry[r].length; c++) {
if (arry[r][c] > max)//找出數組最大值,用於判斷玩家的方塊是否達到2048
max = arry[r][c];
if (arry[r][c] == 0) {
for (int r1 = r + 1; r1 < arry[c].length; r1++)
if (arry[r1][c] != 0) {
arry[r][c] = arry[r1][c];
arry[r1][c] = 0;
count++;//判斷是否發生移動,並且作為輸贏判斷的標準之一
break;
}
}
}
通過雙層循環,循環每一個值,如果它為0,則可以往上移動。遍歷該值所在列,找到第一個不為0的值,移動這個值(即交換兩個數的值)。移動後退出內層循環,繼續遍歷下一個值。
數字的相加:
使用獨立的算法遍歷數組,在移動方向上的相鄰數兩個相加,然後一個置為0。這裏的算法實現和移動的算法十分相像,需要註意的地方同樣也是break和循環的使用。還有一個要註意的就是:數字的相加要放在數字移動之前來完成,否則會出現移動後的數字空格。
//向左的相加算法
for (int r = 0; r < arry.length; r++)
for (int c = 0; c < arry[r].length; c++)
if (arry[r][c] != 0)
for (int c1 = c + 1; c1 < arry[r].length; c1++)
if (arry[r][c] == arry[r][c1]) {
arry[r][c] *= 2;
score += arry[r][c];
arry[r][c1] = 0;
count++;//判斷是否發生相加,並作為輸贏判斷條件之一。
break;
} else if (arry[r][c1] != 0) {
break;
}
同樣是遍歷數組的每一個值,如果這個值不為0,則找所在行的相鄰的相同的值相加,結束最內層循環。如果相鄰的兩個值不同,也結束最內層循環。兩個break語句的使用,避免了數字之間的跳躍相加。
輸贏的判斷:
2048的贏的規則是,相加數字出現2048,所以只需要判斷數組中是否有一個數字等於2048就行,如果有,就輸出相應的獲勝信息。
2048的輸的規則是,界面已經滿(數組已滿,且無可移動,相加的數字)。個人的判斷方法是全局變量count加上判斷數組是否已滿。count如果等於0,則表示無法移動和相加,配合數組已滿的條件就能判斷玩家已經輸了。
隨機數字的出現:
隨機數字出現的條件是發生移動或者相加,所以判斷然讓使用count。條件成立則調用相應算法實現。
Java版2048