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