文章來源:電腦愛好者作者:張劍
還記得《偷天換日》中精靈般穿梭在好萊塢車陣中的Minicooper嗎?馬克・華伯格和莎莉・賽隆就是駕駛著它在仇人的鼻子底下運走了價值千萬的黃金。可是,如果現在將一輛無法賓士的Minicooper軀殼放在你的面前,你會如何看待它?它還是那個遊走自如的精靈嗎?今天,就讓我們一點一點地為這輛Minicooper組裝上零件,讓它跑起來。
前言
從本期開始,我們為大家提供完整的遊戲原始碼(點擊下載)。 Java咖啡館倡導大家理論與實踐並重,我們在連載中將為大家介紹關鍵技術以及實現思路,朋友們自行結合文章閱讀源代碼,好比一邊讀報一邊喝咖啡,這才是滴滴香濃意猶未盡。
遊戲佈局
「連連看」屬於一款二維戰棋遊戲,要設計棋盤類的遊戲,GridLayout應該是不二之選。現在讓我們一起來看看GridLayout的建構子:
・GridLayout():預設的情況下,將佈局區域分割為1*1的大小
・GridLayout(int rows,int cols):指定佈局區域橫向和縱向的格子數
・GridLayout(int rows,int cols,int hgap,int vgap):同上,並且還指定了每個格子之間的橫向間距hgap和縱向間距vgap
千萬別讓這三個構造函數把你給嚇住了,其實只要你喜歡,完全可以放心大膽地使用其中的任何一個,就算不小心用“錯”了,以後也有辦法進行調整。惟一要注意的是,GridLayout在新增控制項時,預設順序是從左上方向右下方依序新增的。
現在讓我們來確定遊戲的格子數目。究竟多少格子比較適合呢?太少會降低遊戲的難度,太多又會造成視覺影響。所以,我們應該透過一對常數來表示,將來即使要修改,也是舉手之勞。
在Java中,常數的定義需要寫成public final static的形式,假如我們規定遊戲的棋盤在橫向有8個格子,縱向也有8個格子,那麼,我們應該這樣定義:
public final static int ROW = 8;
public final static int COLUMN = 8;
然後,我們使用GridLayout的第二個建構子來建立佈局:
GridLayout gridLayout = new GridLayout(ROW, COLUMN);
最後,我們還需要將遊戲區(contentPanel)的佈局改為上述佈局:
contentPanel.setLayout(gridLayout);
如果你此時編譯並執行程式的話,你可能會奇怪:介面怎麼沒有發生任何改變,是不是哪出錯了?雖然我們指定了佈局,可是什麼控制也沒有添加,當然就看不出變化。現在讓我們一起在佈局上新增按鈕吧:
for (int i = 0; i < ROW * COLUMN; i++) {
JButton button = new JButton("Kyodai");
contentPanel.add(button);
}
再運行程式試試,是不是跟我的一樣(見圖1)?
巧用JButton做文章
JButton是一個按鈕控件,它也是Swing中普通得不能再普通的控件了,儘管如此,我們還是需要花費一點功夫來了解和使用它,因為當你能夠熟練使用JButton後,你會發現其他的Swing控件也是如此的相似。
如果你將剛才寫好的程式拿來運行,你會發現:遊戲區的按鈕總是排得滿滿的,這對實際遊戲的操作非常不便,所以,我們得想辦法讓一部分格子空出來。 GridLayout佈局什麼都好,就是在新增控制項的時候不能跳過某一個格子,這下可怎麼辦呢?
其實這也不難,既然GridLayout不讓跳過,如果我們讓某個格子內添加的控制與GridLayout佈局的背景融為一體,這樣在視覺上就達到了一致的效果。此外,如果別人在無意中點擊到這個格子上,按鈕仍然就會原形畢露,我們還得想辦法讓按鈕不能被點擊,這就需要用到JButton的setEnabled()方法。最後,對於能夠點擊的按鈕,當它們被點擊時,我們還得要區分出究竟是哪一個按鈕被點擊了。
在上一次實作「關於」功能的時候,我們使用了e.getSource()方法來判斷滑鼠點擊事件產生的來源,然而,那隻對已經命名好了的控制項比較有效。這裡,使用陣列表示按鈕無疑是最好的方法了,首先讓我們將上面的程式碼修改一下:
JButton[] dots = new JButton[ROW * COLUMN];
for (int i = 0; i < ROW * COLUMN; i++) {
dots[i] = new JButton("Kyodai");
dots[i].setActionCommand("" + i);
contentPanel.add(dots[i]);
dots[i].addActionListener(this);
}
千萬別忘了在循環體中寫上dots[i] = new JButton("Kyodai"),雖然在前面定義、使用了dots組數,然而,這僅僅只是告訴程式我們需要使用一些JButton,但是,這些JButton卻依然沒有被初始化。同時,我們不僅使用setActionCommand()為按鈕制定了事件名稱,還使用了addActionListener()方法為每個按鈕加上了事件回應處理。
關於事件回應的程式碼,我們可以在原來actionPerformed()事件程式碼的後面加上:
if (e.getSource() instanceof JButton) {
JButton button = (JButton) e.getSource();
int offset = Integer.parseInt(button.getActionCommand());
int row, col;
row = Math.round(offset / COLUMN);
col = offset - row * COLUMN;
JOptionPane.showMessageDialog(this,"ROW="+row+",COL="
+ col, "按鈕", JOptionPane.INFORMATION_MESSAGE);
}
在上面的程式碼中,e.getSource() instanceof JButton用來判斷產生的事件是否是由JButton型的控制項產生的,然後又將產生事件來源的控制項進行強制型類別轉換,再使用Integer.parseInt(button .getActionCommand())方法將取得的事件名稱轉換為整數,後面的程式碼就將這個整數還原成行和列的資訊。
好了,現在運行程序,然後點擊每個按鈕,看看是否會出現如右圖的對話框?
注意哦,我們的下標是從0開始的。本期程式原始碼(點擊下載)。
在Swing使用圖片
目前我們已經解決了使用者操作的問題。為了讓介面美觀起來,我們需要使用圖片來取代文字。有時間和耐心的朋友可以自己做個性圖片,只是要注意保持每張圖片大小一致,否則就太難看啦。想省事的話也可以直接使用下載包中提供的圖片。
在Swing中,可以使用setIcon(Image image)方法來為JButton設定圖片,其中的參數image就是我們要設定的圖片對象,這個對像有多種方法可以得到:
・使用Toolkit類別來取得:
image = Toolkit.getDefaultToolkit().getImage(url);
・使用ImageIcon類別的getImage()方法來取得:
image = new ImageIcon(getClass().getResource(filename)).getImage();
我們這裡選用第一種方法。為了方便今後再次獲得Image對象,我們可以將此寫成一個函數:
Image getImage(String filename){
URLClassLoader urlLoader = (URLClassLoader) this.getClass().getClassLoader();
URL url = null;
Image image = null;
url = urlLoader.findResource(filename);
image = Toolkit.getDefaultToolkit().getImage(url);
return image;
}
有了這個函數之後,以後再用到圖片就方便多了,不是嗎?
圖片現在已經有了,那麼我們就可以將原始碼包中Map.Java中的地圖資訊以圖片的形式表現出來了。由於此段程式碼是關於遊戲的演算法程式碼,因此不再列舉程式碼,在這裡大致解釋一下具體是怎麼做的吧!在Map.Java中,我們使用了二維數組map[][]來保存圖片訊息,同時,我們也使用了一維數組images[]來保存每一個圖片對象,map中的每一個元素都有一個值,這個值不僅顯示了在遊戲介面中按鈕對應的值,也顯示了這個按鈕使用images[]數組中圖片的編號,程式運行介面便漂亮許多。
小結
今天我們介紹了Swing中JButton控制項。對大多數Swing控制項來說,JButton的用法一樣可以照搬過去。別小看這個JButton,當你能夠很好地掌握它的時候,你的Swing功底就已經提升一個台階了。此外,我們也學會了在Java中載入圖片檔案的兩種方法。最後,我們還將以上的兩部分內容結合在一起創造了一個漂亮的遊戲介面。雖然我沒有在這裡寫出完整的程式碼,但我相信大家參考我的原始程序,經過自己的努力,一定能夠達到目標。如果遇到解決不了的問題,可以透過[email protected]信箱與我聯絡。
不知道大家對今天的內容感覺到滿意嗎?精彩還在後面,大家要繼續光顧我們的咖啡館!