薛 鵬 段華瓊*
(四川大學(xué)錦城學(xué)院 計(jì)算機(jī)與軟件學(xué)院,四川 成都611371)
俄羅斯方塊最早是由俄羅斯人阿列克謝·帕基特諾夫于1984 年6 月發(fā)明的一款經(jīng)典游戲。俄羅斯方塊游戲是在一個(gè)固定邊界的界面中,不同方塊隨機(jī)出現(xiàn)在上邊界,玩家通過(guò)鍵盤(pán)上的asd(左下右)以及空格(形狀變化)操控,通過(guò)控制空格鍵來(lái)改變方塊的形狀,讓方塊落到邊界的底部。滿行的方塊將會(huì)被消除并且獲得相應(yīng)的分?jǐn)?shù),如果沒(méi)有滿行則方塊的高度會(huì)一直往上面疊加,當(dāng)疊加的方塊到達(dá)頂端的時(shí)候,判定為游戲的結(jié)束。
在實(shí)現(xiàn)游戲時(shí),需要先用二維數(shù)組來(lái)繪制地圖和顯示下一個(gè)將會(huì)出現(xiàn)方塊的邊框,并且在這些位置輸出來(lái)表示墻體,邊框那個(gè)位置坐標(biāo)的值賦為1。地圖其他位置坐標(biāo)的初始值賦為0。用一個(gè)基類(lèi)來(lái)表示方塊的種類(lèi),每一種不同的方塊都繼承該基類(lèi)。方塊的下落過(guò)程用方塊的坐標(biāo)位置更新來(lái)體現(xiàn)(在新的位置來(lái)打印出方塊,在原來(lái)位置上打印空格,以此實(shí)現(xiàn)視覺(jué)上方塊的移動(dòng))。方塊的移動(dòng)用遍歷的方式來(lái)進(jìn)行判斷,對(duì)方塊的周?chē)M(jìn)行遍歷,如果不符合遍歷的條件,則表示方塊不能變形或者移動(dòng)。玩家通過(guò)控制ads 三個(gè)鍵位分別控制方塊的左移、右移,使用空格按鍵來(lái)對(duì)滿足變形條件的方塊進(jìn)行形狀的改變。當(dāng)方塊到達(dá)最底端的時(shí)候?qū)⒎綁K坐標(biāo)位置的值賦為2(不賦為1是因?yàn)閴w所在坐標(biāo)位置的值是1,被固定了的方塊坐標(biāo)所在位置的賦為2 將其與墻體產(chǎn)生區(qū)別)。在游戲過(guò)程中,玩家通過(guò)自己所控制的方塊從底部往上面堆積。如果堆積的方塊填滿了一層,將清除這一層所有的方塊并且這一層上面所有的方塊向下挪動(dòng)一個(gè)單位。在消除該層方塊后將會(huì)獲得相應(yīng)分?jǐn)?shù)的增加。每消除一層方塊,方塊下落的速度將會(huì)增加,隨著消除方塊層數(shù)的增加,方塊的下落速度會(huì)越來(lái)越快,以此來(lái)提升游戲難度。當(dāng)新產(chǎn)生的方塊下面有堆積的方塊時(shí)判定為游戲失敗,游戲失敗后顯示存活秒數(shù)以及獲得的分?jǐn)?shù)。可以將整個(gè)俄羅斯方塊游戲分為以下三個(gè)環(huán)節(jié):第一個(gè)環(huán)節(jié):初始化游戲界面,繪制游戲邊框,以及在邊框右側(cè)顯示第一個(gè)將要出現(xiàn)的方塊。第二個(gè)環(huán)節(jié):根據(jù)玩家的操作,方塊不停的積累或者消除,隨著消除方塊行數(shù)的增加獲得的分?jǐn)?shù)也到相應(yīng)得到增加。每消除一行方塊,方塊下落速度將會(huì)變得更快。第三個(gè)環(huán)節(jié):隨著沒(méi)有被消除方塊的積累,當(dāng)新出現(xiàn)的方塊下面已經(jīng)有了堆積的方塊時(shí),判定游戲結(jié)束。顯示存活秒數(shù)以及獲得分?jǐn)?shù)。
該種父類(lèi)中包含方塊的坐標(biāo)結(jié)構(gòu)體數(shù)組,造型類(lèi)型函數(shù),運(yùn)動(dòng)狀態(tài)檢測(cè)函數(shù),能否改變形狀檢測(cè)函數(shù),方塊的打印與清除函數(shù),檢測(cè)游戲死亡函數(shù)等等。
這個(gè)結(jié)構(gòu)體記錄了每一個(gè)方塊的x 坐標(biāo)以及y 坐標(biāo),在方塊的基類(lèi)中用結(jié)構(gòu)體數(shù)組來(lái)表示四個(gè)方塊。
這是一個(gè)虛函數(shù),因?yàn)槊總€(gè)方塊的變形方式不同,所以要把這個(gè)函數(shù)設(shè)置為虛函數(shù),避免繼承中產(chǎn)生的二義性問(wèn)題。
這個(gè)函數(shù)的作用是檢測(cè)方塊的狀態(tài),檢測(cè)方塊是否應(yīng)該被固定,如果下面有其他方塊了,那么這個(gè)方塊就應(yīng)該被固定了。具體實(shí)現(xiàn)是:使用for 循環(huán)進(jìn)行遍歷每個(gè)方塊下面那個(gè)位置的值,當(dāng)檢測(cè)到當(dāng)前所有方塊中的某一個(gè)方格下面的坐標(biāo)位置處的值不為0 的時(shí)候,那么就將這個(gè)方塊固定。然后將全局變量CreatFangKuai 賦為1,表示可以產(chǎn)生新的方塊,以達(dá)到可以連續(xù)生成新方塊的目的。將state 賦為0,代表方塊不可移動(dòng)。再把當(dāng)前這些方塊坐標(biāo)位置的值修改為2,以便和墻體產(chǎn)生區(qū)別。
bool checkCanLeft()檢測(cè)能否左移,bool checkCanRight()檢測(cè)右移,bool checkCanDown()檢測(cè)是否快速下移。
拿左移舉例,最開(kāi)始讓bool flag=true,方塊最開(kāi)始默認(rèn)為可以左移。然后使用循環(huán)遍歷每個(gè)位置的左側(cè),當(dāng)有一個(gè)方塊的左側(cè)不為0(即墻體或者出現(xiàn)其他的方塊)時(shí),就不允許左移(if(MapValue[fangKuai[i].x-2][fangKuai[i].y]!=0))。右移與左移類(lèi)似。注意,此處x+2 的原因是因?yàn)槊總€(gè)在x 軸上面占兩個(gè)寬度。下移則是if(MapValue[fangKuai[i].x][fangKuai[i].y+1]! =0)。值得關(guān)注的是:在電腦的坐標(biāo)系中,往下移動(dòng)應(yīng)該是y 軸方向上加1,最左上角是看作為坐標(biāo)原點(diǎn),往下方向設(shè)為y 軸的正方向,與常規(guī)的平面直角坐標(biāo)系稍有區(qū)別。
代表速度的全局變量DownSpeed 的初始值為1,DownSpeed=sumScore/10+1。sumScore 記錄游戲分?jǐn)?shù),使用這個(gè)函數(shù)可以讓方塊下落的速度隨著游戲分?jǐn)?shù)的提高而提高。從而慢慢的提高游戲的難度。
這個(gè)函數(shù)的實(shí)現(xiàn)是使用雙重for 循環(huán),在指定位置上打印出空格符號(hào),從而達(dá)到清空指定位置上的方格的目的。
用函數(shù)void drawNextFangkuai(int a,int b)實(shí)現(xiàn)。需要先使用clearNextFangkuai()函數(shù),清空上一次出現(xiàn)在預(yù)測(cè)位置的方塊。隨機(jī)傳入a,b 兩個(gè)值。在這個(gè)函數(shù)中有一個(gè)switch 語(yǔ)句,這個(gè)語(yǔ)句枚舉出每一種可能出現(xiàn)的情況,a 值代表對(duì)應(yīng)方塊的種類(lèi),b 值代表該種方塊的朝向,以此來(lái)預(yù)測(cè)并繪制下一次出現(xiàn)的方塊,讓玩家提前做好應(yīng)對(duì)策略。
由函數(shù)int keydown()實(shí)現(xiàn)。這個(gè)函數(shù)用于接收asd 以及空格四個(gè)按鍵的信息。該函數(shù)的作用是:當(dāng)按鍵被按下時(shí),發(fā)生keydown 事件(或者發(fā)生keydown 事件時(shí)調(diào)用相應(yīng)的函數(shù))。為了防止有多次無(wú)效的輸入,所以設(shè)計(jì)了一個(gè)循環(huán),當(dāng)里面有數(shù)據(jù)的時(shí)候,循環(huán)取出,只使用最后一次的輸入,具體代碼如下:
由函數(shù)void gotoXY(int x,int y)實(shí)現(xiàn)。傳入光標(biāo)需要移動(dòng)的目標(biāo)位置的x 坐標(biāo)和y 軸坐標(biāo)即可將光標(biāo)的位置發(fā)生改變。在該程序中光標(biāo)移動(dòng)函數(shù)的作用非常的大,可以將光標(biāo)移動(dòng)到指定的位置處去,需要注意的是,使用這個(gè)函數(shù)必須包含頭文件windows.h。使用這個(gè)函數(shù)可以很大程度上方便地圖的打印工作。
int getRandRange(int min,int max)是一個(gè)自定義的函數(shù),內(nèi)容是return rand()%(max-min+1)+min;可以用這個(gè)函數(shù)返回一個(gè)min 到max 之間的隨機(jī)整數(shù),以此來(lái)模擬下一次隨機(jī)出現(xiàn)的方塊類(lèi)型。
由函數(shù)checkDeath()實(shí)現(xiàn)。這個(gè)函數(shù)用在各個(gè)方塊類(lèi)的構(gòu)造函數(shù)里面。具體是實(shí)現(xiàn)代碼是:if (MapValue [fangKuai[i].x][fangKuai[i].y]! = 0)。如果新的方塊剛剛生成時(shí)下面就有其他方塊則判定游戲失敗。它的原理是:將所有積累的方塊的坐標(biāo)處那個(gè)位置的值賦為2,待新方塊生成后判斷新生成方塊的位置處的值是否為0,如果不為0 則結(jié)束游戲。
論文基于C++語(yǔ)言提供了俄羅斯方塊游戲的設(shè)計(jì)思路和實(shí)現(xiàn)方法。程序每個(gè)功能都由一個(gè)函數(shù)具體實(shí)現(xiàn),設(shè)置了方塊的基類(lèi),充分展現(xiàn)了程序的模塊化設(shè)計(jì)和C++中面相對(duì)象編程的兩種編程思想。通過(guò)實(shí)踐俄羅斯方塊游戲的設(shè)計(jì)與實(shí)踐,能充分鍛煉模塊化編程的思想以及加深對(duì)C++的理解與掌握。