茍雨晴 蘭全祥
摘要:利用Java的圖形界面和圖形圖像繪制、鼠標(biāo)監(jiān)聽以及鍵盤監(jiān)聽等技術(shù)實現(xiàn)了一個拼圖游戲。對拼圖游戲的功能進行分析和設(shè)計,實現(xiàn)了拼圖隨機打亂、難度設(shè)置、移動次數(shù)統(tǒng)計、原圖預(yù)覽、還原檢測以及排行榜等功能?;贘ava的拼圖游戲設(shè)計與實現(xiàn)綜合了Java開發(fā)基礎(chǔ)、Java反射、事件處理、圖形界面編程以及多線程等知識,不僅對Java課程的教學(xué)有一定的輔助作用,還能提高學(xué)習(xí)者對Java的興趣,鍛煉程序設(shè)計思維。
關(guān)鍵詞:swing;拼圖;游戲開發(fā);事件處理
中圖分類號:TP311? ? ? 文獻標(biāo)識碼:A? ? ? 文章編號:1009-3044(2019)02-0045-03
1 概述
拼圖游戲一般是以九宮格形式展現(xiàn),玩家通過鼠標(biāo)或者鍵盤移動其中某一滑塊將亂序的圖片還原,圖片還原則游戲成功[1]。Java作為目前最流行的編程語言之一,在JDK 1.2之后的java.swing包、java.awt包中提供了功能強大的圖形用戶界面設(shè)計,開發(fā)人員可以使用少量的代碼設(shè)計具有界面效果的游戲[2]。
本文在Java Swing的基礎(chǔ)上,利用Java的圖形界面、多線程和事件監(jiān)聽等技術(shù)來實現(xiàn)此拼圖游戲[3]。對拼圖游戲的功能進行分析和設(shè)計,實現(xiàn)了拼圖原圖預(yù)覽、隨機打亂、難度設(shè)置、移動次數(shù)統(tǒng)計、還原檢測以及排行榜等功能。
2功能分析與設(shè)計
2.1功能設(shè)計
設(shè)計完成一個拼圖游戲需要實現(xiàn)以下功能:
1)游戲初始化:程序運行,啟動游戲窗口。游戲窗口包括為玩家提供操作方法的功能區(qū)以及供玩家拼圖的游戲區(qū)。
2)游戲難度設(shè)置:玩家可以自由改變游戲難度。游戲難度分為入門(3行3列)、一般(4行4列)、困難(5行5列)三個級別,同時圖片也將分割成不同的塊數(shù)。
3)圖片亂序:玩家點擊“開始游戲”之后,程序?qū)㈦S機打亂所有滑塊。打亂之后應(yīng)保證可以還原。
4)步數(shù)統(tǒng)計:玩家可以利用鼠標(biāo)點擊滑塊或鍵盤控制滑塊進行移動,每移動一次步數(shù)加一,并在界面上顯示移動的總步數(shù)。
5)排行榜:在游戲開始前,玩家可以查看游戲排行榜;在游戲結(jié)束后,玩家可以輸入自己的名字,游戲會根據(jù)步數(shù)計算分?jǐn)?shù)并更新排行榜。
6)退出游戲:點擊結(jié)束游戲按鈕和窗口上的關(guān)閉按鈕都可以結(jié)束游戲。
2.2游戲界面
本游戲利用Swing的相關(guān)組件實現(xiàn)游戲界面,如圖1所示。
游戲界面主要分為上下兩個區(qū)域,上方區(qū)域為功能區(qū),包括預(yù)覽、計步、難度設(shè)置、開始游戲、結(jié)束游戲、排行榜等功能按鈕;下方區(qū)域為游戲區(qū),玩家在此區(qū)域進行拼圖游戲。
3 游戲設(shè)計與實現(xiàn)
3.1游戲整體設(shè)計
通過對游戲需求進行分析,對所需對象及功能進行抽象和封裝,形成游戲整體類圖,如圖2所示。
3.2 功能實現(xiàn)
3.2.1 游戲初始化
游戲初始化階段,主要對游戲界面進行生成并在游戲區(qū)中加載拼圖游戲圖片。游戲區(qū)初始化時,根據(jù)圖片的寬度和高度以及游戲難度使用BufferedImage類的getSubimage()方法將對圖片進行分割,然后使用繼承了JButton的Cell類來保存所有的滑塊,并使用javax.swing.Icon類的方法將分割之后的圖片設(shè)置給Cell類的對象,其實現(xiàn)的關(guān)鍵代碼如下。
cells[index] = new Cell(new ImageIcon(image), index, width, height);
其中,image是分割之后的圖片,index是滑塊的下標(biāo),width和hight是滑塊的寬度和高度。
3.2.2 游戲難度設(shè)置
本游戲采用下拉列表進行游戲難度的設(shè)置。在下拉列表中添加入門、一般和困難三個值,并為下拉框設(shè)置監(jiān)聽事件。當(dāng)下拉列表的值發(fā)生改變之后,游戲區(qū)將根據(jù)新的難度重新分割圖片并加載新的游戲面板。
comboBoxn.addItemListener(
new ItemListener() {
public void itemStateChanged(ItemEvent e){/*根據(jù)所選游戲難度重置游戲面板*/});
3.2.3 開始游戲
隨機獲得不同的移動方向(上下左右,分別用0-3數(shù)字表示),然后將白色滑塊與該方向上的滑塊進行交換[4]。重復(fù)執(zhí)行10*col*row次交換后既實現(xiàn)了隨機打亂,且能保證能經(jīng)過有限次移動能夠?qū)⑵磮D還原[5]。
int times = row * col * 10;
Random random = new Random();
for (int i = 0; i < times; i++) {
int dir = random.nextInt(4);
move(blankCell,dir); } }
其中,move(blankCell,dir)方法表示空白滑塊向dir方向移動。當(dāng)空白滑塊向dir方向移動時,該方向上的其他滑塊移動至空白滑塊處。
3.2.4 滑塊移動(鍵盤、鼠標(biāo))
玩家可以通過鍵盤或鼠標(biāo)將滑塊向上下左右四個方向移動,因此本文設(shè)計并實現(xiàn)了方向枚舉類、移動方法move、鍵盤監(jiān)聽以及鼠標(biāo)監(jiān)聽。
1)方向枚舉
定義方向枚舉類Direction,存放上下左右四個方向。
public enum Direction {
UP,DOWN,LEFT,RIGHT}
2)move方法
圖片移動方法的本質(zhì)是將滑塊的坐標(biāo)直接設(shè)置為目標(biāo)位置坐標(biāo),目標(biāo)位置坐標(biāo)將由當(dāng)前滑塊位置以及移動方向來決定,部分關(guān)鍵代碼如下。
Rectangle rec = getBounds();
switch (dir) {
case UP:// 向上移動
if (rec.y - HEIGHT>=0) {
setLocation(rec.x, rec.y- HEIGHT);
}break;
/*省略其他方向移動代碼*/
其中dir表示移動方向的枚舉,HEIGHT表示滑塊的高度。
3)鍵盤監(jiān)聽
要實現(xiàn)鍵盤移動滑塊功能,則需要對游戲窗體進行鍵盤事件監(jiān)聽,因此對游戲窗體GameFrame添加keyPressed事件監(jiān)聽。當(dāng)監(jiān)聽到鍵盤事件時,將觸發(fā)游戲區(qū)中滑塊的移動,關(guān)鍵代碼如下。
int index = e.getKeyCode();
boolean flag = false;
switch (index){
case KeyEvent.VK_W: //按下鍵盤w上升
case KeyEvent.VK_UP:{
flag = swap(cell, Direction.UP);
break;}
需要注意的是由于面板上存在功能區(qū),因此在開始游戲之后應(yīng)使用了setEnabled()方法,禁用面板上的按鈕組件,并使面板重新獲得焦點,以確保鍵盤監(jiān)聽有效。
4)鼠標(biāo)監(jiān)聽
在游戲過程中玩家可以點擊滑塊進行移動。為了實現(xiàn)鼠標(biāo)移動滑塊的功能,在初始化階段將對所有滑塊添加鼠標(biāo)事件監(jiān)聽。
for (int i = 0; i < cells.length-1; i++) {
cells[i].addMouseListener(this);}
當(dāng)鼠標(biāo)點擊滑塊時,先得到該滑塊的坐標(biāo)位置,然后與空白滑塊的橫縱坐標(biāo)位置進行比較,即將滑塊是否能移動轉(zhuǎn)換為數(shù)學(xué)問題[6]。如果兩個剛好相差一個滑塊的高度或?qū)挾龋ù肀稽c擊滑塊剛好位于空白滑塊周圍),則將兩者進行交換;否則,不進行交換。
if (compared(cell, blankCell)==width){ cell.move(Direction.LEFT);
blankCell.move(Direction.RIGHT);}
如果當(dāng)前滑塊與空白塊橫縱坐標(biāo)相差為width,則說明當(dāng)前滑塊在空白塊的右邊,則代表當(dāng)前滑塊可以與空白塊進行交換,即當(dāng)前滑塊左移,空白塊右移。
3.2.5步數(shù)統(tǒng)計
為了對玩家成績進行排名,游戲設(shè)計了計步功能。在程序中定義了一個靜態(tài)變量用于存放游戲步數(shù),當(dāng)點擊鼠標(biāo)或敲擊鍵盤時該靜態(tài)變量的值增加1。
public static void changeStep() {count++;}
3.2.6還原檢測
在游戲開始前,程序?qū)⑹褂靡粋€字符串來存儲未打亂時各個滑塊的位置,然后用另一個字符串來存儲打亂或移動之后的滑塊位置。每次移動滑塊之后都將對這兩個字符串進行比較,如果兩個字符串的值相同,則表示圖片已還原,彈出消息提示框告知玩家拼圖成功。
for (int i = 0; i< cells.length;i++ ){
newStr+=cells[i].getX()+cells[i].getY();}
if(!oldStr.equals(newStr)){return false;}
else{return true;}
3.2.7排行榜
當(dāng)拼圖成功之后,游戲?qū)@示一個消息框供玩家輸入姓名。定義一個玩家信息類PlayerInfo,游戲結(jié)束后程序?qū)⒂毛@取到游戲步數(shù)與玩家姓名初始化該類的對象,并將信息寫入文件score中。當(dāng)用戶點擊排行榜進行查看時,程序?qū)core文件進行反序列化,將文件中的信息讀出并排序,然后使用Graphics重寫paint方法繪制在界面上,排行榜效果圖如下。
4 結(jié)束語
基于Java的拼圖游戲設(shè)計與實現(xiàn)綜合了Java反射、事件處理、圖形界面編程以及多線程等知識,不僅對Java課程的教學(xué)有一定的輔助作用,還能提高學(xué)習(xí)者對Java的興趣,鍛煉程序設(shè)計思維。
參考文獻:
[1] 曹戴. 智能數(shù)字拼圖算法研究及其應(yīng)用[D].無錫:江南大學(xué),2017.
[2] 耿祥義, 張躍平. Java 2實用教程[M]. 4版.北京:清華大學(xué)出版社, 2012.
[3] 張會.基于Java的指法練習(xí)小游戲的設(shè)計與實現(xiàn)[J].電腦知識與技術(shù),2017,13(32):85-86+96.
[4] 黃俊.基于Unity3d拼圖游戲的設(shè)計與實現(xiàn)[J].電子世界,2017(16):145.
[5] JiongXing[EB/OL]. (2018-05-04)[2018-12-14]. https://github.com/JiongXing/PuzzleGame.
[6] 余戰(zhàn)秋.基于App Inventor的九宮格拼圖游戲設(shè)計與實現(xiàn)[J].電腦編程技巧與維護,2017(18):34-36.