JAVA開發類似冒險島的游戲Part1
一、總結
二、JAVA開發類似冒險島的游戲Part1
初學嘛) ,不過總的來說這個程序還是很有意思的。這里我重新再整理了一下,希望能幫助到其他想要開發類似程序的朋友,共同進步!
曬一下效果圖:
哈,還是有模有樣的。左邊是自己寫的冒險島,右邊是真的冒險島。
畢竟也是個游戲,方向鍵可以控制人物移動,然后可以攻擊,可以打怪,升級,做任務。
先說一下素材,有一個專門提供冒險島素材的紙娃娃系統,冒險島中各種素材都可以從這個網站中獲取:
http://www.maplesimulator.com/programs/bannedstory
游戲中顯示出這樣的界面效果,可以用PS中的圖層來理解,所謂圖層就是含有文字或圖形等元素的膠片,一張張按順序疊放在一起,組合起來形成頁面的最終效果。
而這個膠片,就是JAVA中的容器JPanel。JPanel可以設置背景圖片,也可以多個JPanel放置於一個JPanel中,就拿游戲下方的狀態條來說:
整個狀態條就是一個JPanel,我們就新建一個狀態條類
public class StatusBar extends JPanel
然后讓他繼承JPanel。
我們給這個JPanel設置這樣的一個背景:
給JPanel設置背景的方法是重寫JPanel的paint函數,看下面代碼應該很清楚。
public void paint(Graphics g){ g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\狀態條\\狀態條.png"),0,0,this); }
接着,在這個JPanel上還要顯示等級的數字、血條、藍條、經驗條,以及一個系統按鈕(不過其實這個按鈕並不屬於StatusBar類,我們只是讓他顯示在這個位置)。
這些都是StatusBar類的成員。我們只需要在固定的位置將相應的成員顯示就可以了。
先說這個顯示等級的數字,很顯然就是一個JLabel嘛,不過我用的不是JLabel。
依舊是在paint函數中,加入這樣一段:
g.setColor(Color.WHITE); g.setFont(new Font(Font.DIALOG_INPUT, Font.BOLD, 25));//設置字體 g.drawString(Integer.toString(lv), 50,38);//等級
直接把字畫在JPanel上的相應位置就可以了,顏色、字體、大小、字的內容、橫縱坐標,就這些參數。可以查看API文檔,這里就不細說。
血條藍條經驗條,這三個條條是大部分網絡游戲都有的東西,主要用來直觀的顯示玩家狀態,拿血條舉例子,看最前面的效果圖,當前血量800,總血量1000,所以血條的長度就是整個血槽的4/5,這樣一想,用進度條這種組件去實現血條藍條是很可行的,然而我查了才發現,JAVA中(至少是標准庫吧。。)並沒有進度條這個組件,所以還是要自己去實現它。
還是在paint函數中:
g.setColor(Color.RED); //血條 g.fillRect(141, 23, (int)((double)hp/allhp*length), 15); g.setColor(Color.BLUE); //藍條 g.fillRect(340, 23, (int)((double)mp/allmp*length), 15); g.setColor(Color.YELLOW); //經驗條 g.fillRect(539, 23, (int)((double)exp/allexp*length), 15);
根據當前血量和總血量的比例去繪制相應長度相應顏色的矩形,這樣一來動態的血條藍條經驗條的主體部分就完成了,我們還需要在上面顯示具體的血量和血總量:
有了前面繪制等級的經驗,我們使用g.drawString函數就可以了,不過為了顯示的美觀嗎,我們還需要考慮一些問題,文字的顯示是與血條右邊對其的,而繪制文字的參數中提供的參數是這樣的一組x,y並不能符合我們右對其的要求。
所以我用了另外一種很機智(shabi)的方法:
//數字比例6.7619 /[比例3 String hptxt="["+Integer.toString(hp)+"/"+Integer.toString(allhp)+"]"; int hptxtnuml=Integer.toString(hp).length()+Integer.toString(allhp).length();//血量數字顯示的數字長度 int hptxtx=272-(int)(hptxtnuml*6.7619);//相應橫坐標 String mptxt="["+Integer.toString(mp)+"/"+Integer.toString(allmp)+"]"; int mptxtnuml=Integer.toString(mp).length()+Integer.toString(allmp).length();//藍量數字顯示的數字長度 int mptxtx=471-(int)(mptxtnuml*6.7619);//相應橫坐標 String exptxt="["+Integer.toString(exp)+"/"+Integer.toString(allexp)+"]"; int exptxtnuml=Integer.toString(exp).length()+Integer.toString(allexp).length();//藍量數字顯示的數字長度 int exptxtx=670-(int)(exptxtnuml*6.7619);//相應橫坐標
先把要繪制的字符串准備好,然后計算一下文本長度(這個長度是指真的長度。。顯示出來要幾個坐標。。別問我怎么測得,我用尺子量的。。),最后換算出相應的坐標繪制。
至此,狀態條的顯示就完成了。在我的設計中,人物的屬性(血,藍,經驗,等級,攻擊力等)是直接放在狀態條類里作為成員變量的,換句話說,你玩游戲玩的不是那個人物,你的所有數據都不存在人物的類里,而是存在狀態條類里,人物攻擊力高,一下秒掉怪物,那只是配合着狀態條里的屬性顯示給玩家看而已~
我們先把狀態條放到一邊,待會再來用它。
現在我們要實現方向鍵控制人物移動。
依舊是前面圖層的思想,人物也是一個圖層。我們創建一個人物類:
public class Obj extends JPanel
先來分析一下人物的動作,人物有個朝向,臉朝左,臉朝右,站着不動的時候有站着不動的姿勢,走路的時候有走路的姿勢,按上鍵如果能抓到繩子,有爬繩子的姿勢,按下有趴着的姿勢。所以Obj類中需要有一個變量來控制人物的狀態,(向左走、向右走、向左趴下等):
private int zhuangtai=2;//人物狀態
然后在繪制背景圖片的時候,switch(zhuangtai)來決定該繪制哪張圖片就可以了。
我們可以寫一個設置狀態的函數,以便控制人物的時候使用:
public void setzhuangtai(int a)//設置狀態 { zhuangtai=a; }
這里說明一下,人物站立的時候,並不是一張靜止的圖片,而是提前准備好的GIF圖像,站立的時候顯示的就是自然擺手的動畫分鏡頭如下:
當然如果不想使用GIF圖像的話,可以新建一個線程,專門在站立狀態控制人物擺手動畫的切換。
類似攻擊的動畫顯示也是如此。
我們現在先來設想一下控制人物移動的思路:
首先人物這個圖層(JPanel)是顯示在窗口上的,主類繼承JFream
然后人物作為主類的成員,就和創建一個JButton一樣的寫法
private Obj ren=new Obj(0,0);//創建角色
用兩個整形變量x,y來代表人物的坐標
接下來就是將,xy作為參數使用setBounds函數設置人物的顯示坐標以及顯示大小。
對主窗口注冊鍵盤監聽和觸發事件:
我們按下方向鍵后,比如說方向右鍵,調用Obj類中的setzhuangtai函數,修改人物狀態,再將x+5 (這個值自己定,值越大移動的越快)接着再次使用setBounds重新設置人物的顯示坐標。然后調用repaint進行重繪。
這樣就可以實現人物的移動了。我這里沒有附具體代碼,因為我不是這樣寫的。。(噗!!)
在實際測試中,這樣去實現人物移動會引入一個很麻煩的問題——當你設置了游戲地圖之后,控制人物移動會出現背景跟不上人物,有殘影的情形,具體的解決方案是使用雙緩沖技術,不過我有另外的思路解決了這個問題,何樂而不為呢:
人物移動的時候,人物這個圖層后面的背景總是拖着之前的背景,使得顯示着很不協調,我的解決方案是設置人物這個圖層的大小的時候,讓他充滿整個屏幕,這樣的話,人物移動時,背景就是整個屏幕,而不用考慮舊背景的殘影問題了。不過這樣設計的話,人物移動的方式就要改變了,不能再是移動人物類的對象在主窗口中顯示的位置,因為人物類的對象在主窗口中已經是全屏顯示了,不能再改變,改變的只能是人物的圖片,在人物類的這個JPanel中內部的位置。所以x,y這個坐標也是存於人物類中。
private int zhuangtai=2;//人物狀態 //屏幕坐標 private int x; private int y; public void setzhuangtai(int a)//設置狀態 { zhuangtai=a; } public void setxy(int m_x,int m_y) { x=m_x; y=m_y; } //人物在屏幕中移動 public void movex(int m_x) { x+=m_x; } public void movey(int m_y) { y+=m_y; }
顯示的地方就通過x和y的值來調整位置,不過還是有一個地方要注意,顯示圖片時的坐標參數是指以左上角為起點的,但是每一張圖片的大小都不一樣,所以如果不加換算的話就會出現這樣的問題:
人物的顯示坐標自然是要以腳為坐標,所以我們對於每一張圖都要測定它的偏移(很幸運的是紙娃娃系統可以直接導出偏移的值),然后顯示的時候根據偏移去計算換算后的坐標。
paint函數如下:
public void paint(Graphics g)
{ switch(zhuangtai) { case 0:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\走路\\向右走0.png"),x-15,y-68,this);break; case 1:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\走路\\向右走1.png"),x-15,y-68,this);break; case 2:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\走路\\向右走2.png"),x-15,y-68,this);break; case 3:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\走路\\向右走3.png"),x-15,y-68,this);break; case 4:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\走路\\向左走0.png"),x-76,y-68,this);break; case 5:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\走路\\向左走1.png"),x-76,y-68,this);break; case 6:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\走路\\向左走2.png"),x-76,y-68,this);break; case 7:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\走路\\向左走3.png"),x-76,y-68,this);break; case 8:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\站立\\面朝右站.gif"),x-40,y-86,this);break; case 9:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\站立\\面朝左站.gif"),x-24,y-86,this);break; case 10:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\跳躍\\向右跳.png"),x-40,y-90,this);break; case 11:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\跳躍\\向左跳.png"),x-25,y-90,this);break; case 12:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\趴下\\面朝左趴下.png"),x-106,y-40,this);break; case 13:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\主角\\趴下\\面朝右趴下.png"),x,y-40,this);break; case 14:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\0.png"),x-165,y-110,this);break; case 15:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\1.png"),x-165,y-110,this);break; case 16:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\2.png"),x-165,y-110,this);break; case 17:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\3.png"),x-165,y-110,this);break; case 18:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\4.png"),x-165,y-110,this);break; case 19:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\5.png"),x-165,y-110,this);break; case 20:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\6.png"),x-165,y-110,this);break; case 21:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\7.png"),x-165,y-110,this);break; case 22:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\左\\8.png"),x-165,y-110,this);break; case 23:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\0.png"),x-115,y-110,this);break; case 24:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\1.png"),x-115,y-110,this);break; case 25:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\2.png"),x-115,y-110,this);break; case 26:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\3.png"),x-115,y-110,this);break; case 27:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\4.png"),x-115,y-110,this);break; case 28:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\5.png"),x-115,y-110,this);break; case 29:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\6.png"),x-115,y-110,this);break; case 30:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\7.png"),x-115,y-110,this);break; case 31:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory\\圖片素材\\技能\\輕舞飛揚\\右\\8.png"),x-115,y-110,this);break; case 32:g.drawImage(Toolkit.getDefaultToolkit().getImage("F:\\Code\\JAVA\\MapleStory