吳錦濤 薛益鴿
摘 要: 作為全世界使用率最高的語言,Java以其獨(dú)特的魅力吸引了眾多程序員。Java雖然在大型游戲的制作上并非最方便的選擇,但是在經(jīng)典小游戲上的制作上卻有著獨(dú)一無二的技術(shù)優(yōu)勢。考慮到當(dāng)前許多網(wǎng)上的小游戲模型代碼不是那么簡潔,對于初學(xué)者并不友好,所以本文在基于一些網(wǎng)絡(luò)代碼的研究后進(jìn)行了Java語言桌面小程序的探討開發(fā),使得Java語言方便,簡潔的優(yōu)點(diǎn)得到了更好的體現(xiàn)。
關(guān)鍵詞: Java;棧;三段式;推箱子
Abstract:As the world's most-used language Java has attracted many programmers with its unique charm. Although Java is not the most convenient choice for the production of large-scale games the production of classic mini-games has the outstanding technologyical advantages. Considering that many current online game models are not so simple and not friendly to beginners after studying some network code this paper discusses and develops the Java language desktop applet making the convenience and conciseness of Java language can be better reflected.
Key words: Java;stack;Triade;box
1 Java語言概述
Java語言自問世以來,即已經(jīng)歷了長期的發(fā)展演變過程。發(fā)展至今,Java語言對于專業(yè)程序員而言,如果不能精熟運(yùn)用,這里可打個通俗比喻,即如一名音樂家不識樂譜。Java是一門面向?qū)ο缶幊陶Z言,不僅吸收了C++語言的許多優(yōu)點(diǎn),而且摒棄了C++中晦澀高深的部分,因而正在當(dāng)今的軟件開發(fā)領(lǐng)域發(fā)揮著至關(guān)重要的基礎(chǔ)模式作用。
分析可知,Java語言獲得了大范圍的廣泛應(yīng)用。究其原因,可闡釋論述如下:
(1) Java語言的簡易性。Java語言在語法上都與C語言以及C++語言非常接近,因此對于大多數(shù)程序員來說,學(xué)習(xí)Java將更加容易。同時,Java舍棄了C++中少用、難懂的部分,并且Java語言中的數(shù)組和串都是對象,因而就不再需要指針方面的設(shè)計(jì)。
(2)Java語言面向?qū)ο蟮奶攸c(diǎn)。Java語言中使用類、繼承、接口等多種原語。當(dāng)然,在使用過程中,類的繼承是單一的,而接口之間是多繼承。Java中還包括各種package,用戶在面對各種需求時可以在頭部加入擴(kuò)展包,例如javax-mail-1.3.jar 等。
(3)Java語言的安全性。Java語言多用于網(wǎng)絡(luò)環(huán)境,所以Java提供了一種可以防止惡意代碼的安全機(jī)制。就Java未設(shè)指針這一特點(diǎn),他人將無法探知程序背后的詳情內(nèi)幕和偽造指針去指向存儲器。
(4)Java語言的動態(tài)性。Java語言設(shè)計(jì)的重要目的之一就是可以適應(yīng)動態(tài)的環(huán)境變化。Java的類是基于設(shè)計(jì)需要而靈活載入環(huán)境中的,甚至某些時候是通過網(wǎng)絡(luò)來獲取。
2 Java的應(yīng)用領(lǐng)域
作為廣受歡迎的編程語言之一,Java語言在生活和科技領(lǐng)域中有著不可估量的作用與影響。在許多方面,諸如從電子商務(wù)網(wǎng)站到Android應(yīng)用,從各類游戲到桌面的應(yīng)用程序,即如人們熟悉的Eclipse,IntelliJ等等。接下來,將會針對一些相對重要的領(lǐng)域應(yīng)用,給出概述如下。
2.1 Android應(yīng)用
Java距離大眾最近的應(yīng)用是什么?這個問題的答案觸手可及,那就是每天都在使用的安卓手機(jī),幾乎其中的所有應(yīng)用都使用了Java匯編。
2.2 應(yīng)用程序服務(wù)
不論在金融服務(wù)行業(yè)的服務(wù)器應(yīng)用程序,或是Java Web應(yīng)用程序,亦或是其它軟件工具,對當(dāng)今的社會運(yùn)行都具有重大的推動作用。尤需一提的就是廣泛的軟件開發(fā)工具,如Eclipse、InetelliJ Idea和Netbans IDE。
3 Java在游戲領(lǐng)域的開發(fā)
近年來,游戲產(chǎn)業(yè)的蓬勃發(fā)展給計(jì)算機(jī)行業(yè)掀起了一股更新熱潮。如果說前10年的游戲設(shè)計(jì)初衷是為了娛樂和休閑,但經(jīng)過這一時期的萃取演練,現(xiàn)在的游戲則日趨職業(yè)化,不論是游戲制作者、或者是游戲玩家,都在對游戲提出更高層次的發(fā)布需求。作為游戲服務(wù)器中的王者,Java在游戲編譯中也占據(jù)著舉足輕重的地位。特別是目前手機(jī)已經(jīng)成為人類社交中不可或缺的一部分,手機(jī)游戲隨即大行其道,例如近期知名流行的王者榮耀以及吃雞。所以無論手游、端游,亦或是頁游,都離不開Java的模式參與。
暫且不談那些大型游戲,這里先將研究視角切換到都玩俄羅斯方塊的時期。這也是用Java語言編寫的最早期爆款游戲了。巨大的潛在市場,促進(jìn)了行業(yè)的發(fā)展,此后則陸續(xù)出現(xiàn)了多款到現(xiàn)在都仍耳熟能詳?shù)挠螒颍T如:貪吃蛇(WORM)、泡泡龍、魂斗羅、超級馬里奧等。接下來,即將以經(jīng)典游戲之一的推箱子來解析并展示Java類游戲的設(shè)計(jì)和實(shí)現(xiàn)。
4 Box的發(fā)展設(shè)計(jì)
在借閱參考了前人[1]的一些觀點(diǎn)和試玩了幾款推箱子(Push Box)游戲后,研究發(fā)現(xiàn)最初推箱子游戲的功能清晰簡單,只有最基本的游戲體驗(yàn),所以就有人提出了一定改進(jìn),添加了一些功能選擇,比如選關(guān)、計(jì)分;而后又陸續(xù)加入了音樂或者動態(tài)的人物,以致將其做成2D[2]或者3D等等。版本在不斷地變化,算法和設(shè)計(jì)也在創(chuàng)新升級之中[3]。近期很火的AI想法也正在滲透并融入其中[4]。為此,本文設(shè)計(jì)提出了如下的基于三段式的推箱子游戲研發(fā)過程,對其內(nèi)容可詳述如下。
在游戲的編譯之前,首先要進(jìn)行游戲的需求分析。分析的理念很簡單:一是需要讓游戲如何運(yùn)行,二是該游戲需要滿足玩家何種需求,三是如何實(shí)現(xiàn)游戲和玩家的互動。
為此,就要提供菜單欄的規(guī)劃設(shè)計(jì)。顧名思義,菜單欄是指游戲進(jìn)行多樣化功能或選擇幫助的區(qū)域。當(dāng)然,考慮到游戲的娛樂性,本文的推箱子還具備一個特殊的功能—炸掉擋住前進(jìn)道路的墻。菜單欄的屬性可以根據(jù)用戶需求來依序排布,本文中只定制了3種屬性,分別是:選項(xiàng)、幫助和開掛。二級菜單為:選項(xiàng)(重新開始、上一關(guān)、下一關(guān)、關(guān)卡選擇、退一步、退出)、幫助(請求幫助)、開啟外掛(啟用、關(guān)于外掛)。菜單欄簡潔,則因?yàn)檫@是單機(jī)版,從而不需要配設(shè)很多數(shù)據(jù)與互聯(lián)網(wǎng)之間的傳輸。幫助選項(xiàng)的選擇性信息就豐富許多,既可以包括游戲的玩法,也可以寫入游戲設(shè)計(jì)者的一些信息。至此,就是關(guān)于外掛,設(shè)計(jì)初衷是因?yàn)槔L制一些復(fù)雜地圖時發(fā)現(xiàn)有些道路不一定能走得通,因而就編寫一個功能可以把擋道的墻炸掉。
在菜單欄的分析效果描述后,下一步就是主面板設(shè)計(jì)。本文設(shè)計(jì)為將主界面分為兩部分,一塊(主界面)占據(jù)全界面,另一塊(游戲界面)則被包含在前一塊中,位置居于靠近左下;而在主界面右側(cè),設(shè)計(jì)了9個按鈕(Button),分別是:開始、退一步、第一關(guān)、上一關(guān)、下一關(guān)、最終關(guān)、選關(guān),音樂開關(guān)以及炸彈按鈕。如此配置后,游戲玩家就不再需要通過菜單進(jìn)行一些操作,例如退一步或者選關(guān)等等。并且,這些按鈕也改善了界面的美觀性,使游戲體驗(yàn)趨于良好、以致最佳。這里,將研究給出游戲設(shè)計(jì)的整體流程如圖1所示。
5 Push Box的實(shí)現(xiàn)
Push Box的實(shí)現(xiàn)過程中,首先要創(chuàng)建一個基于JFrame的類mainframe,主要用于設(shè)計(jì)撰寫菜單和頁面布局的代碼,包括按鈕、聲音等。接下來,將開啟本次研究的主題設(shè)計(jì),即如何實(shí)現(xiàn)推箱子的行動,包括:行動、退一步和炸彈。研發(fā)過程可詳見如下。
5.1 地圖的生成
考察分析可知,現(xiàn)在多數(shù)這一類游戲的地圖都使用圖片與數(shù)字結(jié)合,使用數(shù)字圖片一一對應(yīng)的關(guān)系,用數(shù)字來描繪地圖。研究中,數(shù)字化地圖的設(shè)計(jì)示例如圖2所示。
由圖2可知,這是一張20×20的地圖,圖2中的每個數(shù)字都代表了不同的圖片。
其中,鴨子的圖片為5、6、7、8,分別對應(yīng)著正面、左面、右面、背面。但是在制作地圖時,默認(rèn)狀態(tài)下的鴨子是以正面出現(xiàn)的,所以只寫了5代表鴨子,其實(shí)無論將哪種狀態(tài)當(dāng)做鴨子并無大礙。總地來說,0為背景,1為地圖的邊界以及不可通過障礙,2為可移動草地,3為箱子,4為箱子指定到達(dá)的地點(diǎn),9為當(dāng)鴨子將箱子推至目的地后變?yōu)橐恢恍≌卖~。而圖2的數(shù)字,通過代碼的調(diào)用運(yùn)行即可呈現(xiàn)出地圖效果。研發(fā)可得代碼如下:
public class Readmap{
private int level mx my;
private int [][] mymap=new int[20][20];
FileReader r;
BufferedReader re;
String bb=""
int[] x;
int c=0;
Readmap(int k)
{
level=k;
String s;
try{
File f=new File(pathname:"maps\\"+level+".map")
r=new FileReader(f);
re=new BufferedReader(r);
try{
while((s=re.readLine())!=null){
bb=bb+s;
}
}
catch(IOException g)
{
System.out.println(g);
}
byte[] d=bb.getBytes();
int len=bb.length();
int[] x=new int[len];
for(int i=0;i x[i]=d[i]-48; } for(int i=0;i<20;i++){ for(int j=0;j<20;j++){ mymap[i][j]=x[c]; if(mymap[i][j]==5){ mx=j; my=i; } c++; } } public void paint(Graphics g){ for(int i=0;i<20;i++){ for(int j=0;j<20;j++){ g.drawImage(myImage[map[j][i]],x:i*len,y:j*len,observer:this) } }} 由上述代碼段可知,其中定義了一個二維數(shù)組來存儲20×20的地圖數(shù)字,通過File的方式查詢到對應(yīng)的地圖編碼后使用Filereader方式進(jìn)行讀取,并存入BufferedReader。同時,定義一個空字符串,使用while循環(huán)來判斷是否有內(nèi)容。若為有內(nèi)容,則將內(nèi)容存入這一空字符串bb中,這樣就獲取了整張地圖的信息,再通過byte與String的轉(zhuǎn)換,將bb中的內(nèi)容轉(zhuǎn)換為字節(jié)。而且,通過創(chuàng)建一個與bb相同長度的空數(shù)組,采用for循環(huán)將b字節(jié)數(shù)組中的內(nèi)容存放于x數(shù)組中。此后,又通過另一個類中的方式調(diào)用圖片,就完成了地圖的讀取。人物的讀取相對來說要較為簡捷。綜上代碼中,涉及的是一個二維數(shù)組地圖,為此就使用了二重for循環(huán),遍歷地圖每一個數(shù)字,如果有等于5的,即為本次研究的目標(biāo)對象—小黃鴨。
5.2 目標(biāo)的運(yùn)動
本次研發(fā)中,目標(biāo)對象小黃鴨運(yùn)動的部分代碼設(shè)計(jì)可見如下:
public void moveup(){
if(map[manY-1][manX]==2||map[manY-1][manX]==4)
{
if(maptmp[manY][manX]==4||maptmp[manY][manX]==9)
map[manY][manX]=4;
else map[manY][manX]=2;
map[manY-1][manX]=8;
repaint( );manY--;mystack.push (item:10);
}
else if(map[manY-1][manX]==3)
{
if(map[manY-2][manX]==4)
{
if(maptmp[manY][manX]==4||maptmp[manY][manX]==9)
map[manY][manX]=4;
else map[manY][manX]=2;
map[manY-1][manX]=8;
map[manY-2][manX]=9;
repaint();manY--;mystack.push(item:11);
}
}
}
如上即是小黃鴨前進(jìn)的代碼,向左、向右和向后只是改變了manY,manX的數(shù)值,在邏輯方面未見明顯變化,為此這里僅給出向前的代碼作為演繹實(shí)例。尤需指出的是,其中蘊(yùn)含著許多假設(shè)邏輯,如果設(shè)計(jì)上出現(xiàn)缺失,就會導(dǎo)致游戲存在漏洞,甚至無法正常運(yùn)行。
在上述代碼中,map就是地圖,manY與manX為目標(biāo)在二維數(shù)組構(gòu)成的地圖中的坐標(biāo),manY-1在manY的上方一格,其數(shù)值就是在之前提過的地圖組成元素。在前進(jìn)中的一種基礎(chǔ)行為邏輯設(shè)計(jì)就是小黃鴨往上走一步,其本身下面并不存在箱子,箱子指定的位子,僅僅是草坪,其上面一格也是同樣。那么這代碼需要處理的就是將小黃鴨身處的位子變?yōu)椴萜海枮?,上面一格原本為草坪2,變?yōu)樾↑S鴨的背面8,然后使用repaint();將地圖重畫即可。而其它方面的行為邏輯設(shè)計(jì)也將以同樣的改變和重畫作為后續(xù)的推演依據(jù)。
5.3 悔步和退步功能設(shè)計(jì)
當(dāng)需要使用悔步功能時,就要用到棧的概念。棧先進(jìn)后出的特點(diǎn)可恰當(dāng)妥帖地應(yīng)用于悔步設(shè)計(jì)中。當(dāng)小黃鴨開始行動時,常常會向棧里輸入一個數(shù)字。比如,前進(jìn)時輸入10,推著箱子前進(jìn)時輸入11,向左時輸入20,向左推箱子時輸入21,以此類推。使用這種方法,不但可以區(qū)分上一步的方向,也能甄別其是否有推動箱子。如此,就使得研究中的退一步操作更容易實(shí)現(xiàn)。這里即以后退一步作為例示(與向前進(jìn)一步形成對比),關(guān)鍵代碼可展現(xiàn)如下:
public void backup(int t){
int n=t;
if(n==10)
{
if(maptmp[manY][manX]==4||maptmp[manY][manX]==9)
{
map[manY][manX]=4;
}
else map[manY][manX]=2;
}
else if(n==11)
{
if(maptmp[manY][manX]==4||maptmp[manY][manX]==9)
{
map[manY][manX]=9;
}
else map[manY][manX]=3;
if(maptmp[manY-1][manX]==4||maptmp[manY-1][manX]==9)
{
map[manY-1][manX]=4;
}
else map[manY-1][manX]=2;
}
map[manY+1][manX]=8;
repaint();manY++;
}
后退一步的執(zhí)行機(jī)制和前進(jìn)一步較為相似。但需要細(xì)加考慮的是,在進(jìn)行后退一步前,要分類判斷從棧中提取的數(shù)字是什么。如果是10,那么就啟用沒有推動箱子向前走了一步需要退回的操作;如果是11,則判斷已發(fā)生的前進(jìn)一步是有箱子的。因?yàn)檠芯恐械南渥訌牟萜阂苿拥街付ㄎ蛔拥膱D案是會改變成小章魚的,故而需要特別的關(guān)注。
5.4 炸彈功能設(shè)計(jì)
本次研究增加的炸彈功能,是為了提供一定的娛樂性。部分研發(fā)代碼可見如下:
public void zhadan(){
if(map[manY][manX]==5){
if(map[manY+1][manX]==1){
if(map[manY+2][manX]==1&↦[manY+2][manX-1]!=0 &↦[manY+2][manX+1]!=0){
runup();
mic.Music_buff();
}else if(map[manY+2][manX]==2||map[manY+2][manX]==3||map[manY+2][manX]==4){
runup();
mic.Music_buff();
}
}
}
}
public void runup(){
new Thread(new Runnable){
@Override
public void run(){
for(int i=10;i<16;i++){
map[manY+1][manX]=i;
try{
Thread.sleep(millis:100);
}catch(Exception e){
e.printStackTrace();
}
repaint();
}
map[manY+1][manX]=2;
repaint();
}
}).start();
}
炸彈功能即先判斷小黃鴨的朝向,繼而判斷小黃鴨朝向的不可通過障礙是否為邊界墻,雖然地圖中間的墻和地圖外圍的墻組成部分是一樣的,但是在使用炸彈時卻不能炸掉最外圈的墻,所以需要確定判斷小黃鴨面對墻的再前面一格兩側(cè)是否存在0,即背景。如果有,就不能刪除,反之可以。特別地,Runup()這4個類插入的是逐幀動畫,即炸彈爆炸的動畫。
6 結(jié)束語
不論是應(yīng)用開發(fā)還是游戲開發(fā)都在無止境的升級發(fā)展中,設(shè)計(jì)者需要做的就是不斷尋求臻至完美、以及更貼近人性化的設(shè)計(jì)。本文提出的基于三段式的推箱子的研發(fā)設(shè)計(jì)即是基于Java應(yīng)用于小游戲的大膽嘗試,同時也將為未來后續(xù)的創(chuàng)新深入研究提供一個堅(jiān)實(shí)有益的良好基礎(chǔ)。
參考文獻(xiàn)
[1] 秦濤. 跨平臺手機(jī)游戲推箱子的設(shè)計(jì)與實(shí)現(xiàn)[D]. 重慶:重慶大學(xué) 2015.
[2] 潘惠勇 夏敏捷. Java實(shí)現(xiàn)2.5D推箱子游戲[J]. 電腦編程技巧與維護(hù) 2014(19):28-31,56.
[3] 謝玉庚. 用間接遞歸法判斷推箱子游戲的死鎖情況[J]. 電腦開發(fā)與應(yīng)用 2014 (9):30-34.
[4] 陳建氣 鄺廣朋 梁均杰,等. 推箱子游戲中人工智能的進(jìn)一步應(yīng)用[J]. 珠海教育學(xué)院學(xué)報 2003(4):111-112.