編程高手之路—代碼集萃—C語(yǔ)言編寫(xiě)的俄羅斯方塊.doc
《編程高手之路—代碼集萃—C語(yǔ)言編寫(xiě)的俄羅斯方塊.doc》由會(huì)員分享,可在線閱讀,更多相關(guān)《編程高手之路—代碼集萃—C語(yǔ)言編寫(xiě)的俄羅斯方塊.doc(14頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
1、編程高手之路—代碼集萃—C語(yǔ)言編寫(xiě)的俄羅斯方塊 Tc2.0中怎么樣設(shè)置圖形顯示? Tc2.0中有兩種顯示模式,一種是我們所熟知的字符模式,另一種是圖形模式。在字符模式下只能顯式字符,如ASCII字符。一般是顯示25 行,每行80個(gè)字符。程序缺省的是字符模式。在字符模式下不能顯式圖形和進(jìn)行繪圖操作。要想進(jìn)行圖形顯示和繪圖操作,必須切換到圖形模 式下。 Tc2.0中用initgraph()函數(shù)可以切換到圖形模式,用closegraph()可以從圖形模式切換回字符模式。initgraph()和closegraph()都是圖形 函數(shù),使用圖形函數(shù)必須包括頭文件graph
2、ics.h。 void far initgraph(int far *graphdriver,int far *graphmode,char far *pathtodriver);graphdriver是上漲指向圖形驅(qū)動(dòng)序號(hào)變量的指針;graphmode是在graphdriver選定后,指向圖形顯示模式序號(hào)變量的指針。pathtodriver表示存放圖形驅(qū)動(dòng)文件的路徑。 Tc2.0中有多種圖形驅(qū)動(dòng),每種圖形驅(qū)動(dòng)下又有幾種圖形顯示模式。在我的程序中圖形驅(qū)動(dòng)序號(hào)為VGA,圖形顯示模式序號(hào)為VGAHI。這是一種分辨率為640*480(從左到右坐標(biāo)依次為0-639,從上到下坐標(biāo)依次
3、為0-479),能夠顯示16種顏色的圖形模式。別的圖形驅(qū)動(dòng)序號(hào)和圖形顯示模式序號(hào),可以從手冊(cè)或聯(lián)機(jī)幫助中找到。 pathtodriver指示存放圖形驅(qū)動(dòng)文件的路徑。圖形驅(qū)動(dòng)序號(hào)不同,圖形驅(qū)動(dòng)文件也不同。序號(hào)為VGA圖形驅(qū)動(dòng)對(duì)應(yīng)egavga.bgi這個(gè)圖形驅(qū)動(dòng)文件。egavga.bgi一般在Tc目錄下。 void far closegraph(void); 沒(méi)有參數(shù),從圖形模式直接返回字符模式。 initgraph()和closegraph()的常用用法如下: int gdriver = VGA, gmode=VGAHI, errorcode; /* init
4、ialize graphics mode */ initgraph(&gdriver, &gmode, e:tc2); /* read result of initialization */ errorcode = graphresult(); if (errorcode != grOk) /* an error occurred */ { printf(Graphics error: %sn, grapherrormsg(errorcode)); printf(Press any key to halt:); getch(); exit(1); /* return
5、with error code */ } /* return to text mode */ closegraph(); Tc2.0中常用圖形函數(shù)的用法? 在這里講幾個(gè)游戲中用到的繪圖用的圖形函數(shù): setcolor(); line(); rectangle(); settextjustify(); outtextxy(); setfillstyle(); bar(); void far setcolor(int color); 設(shè)置畫(huà)線、畫(huà)框和在圖形模式下顯示文字的當(dāng)前顏色。這個(gè)函數(shù)將影響line()、rectangle()和outtext
6、xy()函數(shù)繪圖的顏色。 color可以取常的顏色常量: BLACK ? 0 BLUE ? 1 GREEN ? 2 CYAN ? 3 RED ? 4 MAGENTA ? 5 BROWN ? 6 LIGHTGRAY ? 7 DARKGRAY ? 8 LIGHTBLUE ? 9 LIGHTGREEN ?10 LIGHTCYAN ?11 LIGHTRED ?12 LIGHTMAGENTA ?13 YELLOW ?14 WHITE ?15 void far line(int x1,int y1,int x2,int y2); 用當(dāng)前顏色從(x1,y1)畫(huà)一條到
7、(x2,y2)的線段。 void far rectangle(int left,int top,int right,int bottom); 用當(dāng)前顏色畫(huà)一個(gè)左上角為(left,top)、右下角為(right,bottom)的矩形框。 void far settextjustify(int horz,int vert); 設(shè)置圖形模式下文字輸出的對(duì)齊方式。主要影響outtextxy()函數(shù)。 horiz和vert可取如下枚舉常量: horiz ?LEFT_TEXT ? 0 ?Left-justify text ?CENTER_TEXT ? 1 ?Center text
8、?RIGHT_TEXT ? 2 ?Right-justify text vert ?BOTTOM_TEXT ? 0 ?Justify from bottom ?CENTER_TEXT ? 1 ?Center text ?TOP_TEXT ? 2 ?Justify from top void far outtextxy(int x,int y,char * textstring); 在(x,y)處用當(dāng)前字體(缺省的字體是DEFAULT_FONT)顯示字符串textstring,字符串的對(duì)齊方式由settextjustify()指定。 void far setfillstyle
9、(int pattern,int color); 設(shè)置圖形的填充模式和填充顏色,主要影響bar()等函數(shù)。 pattern一般取枚舉常量值SOLID_FILL,color的取值與setcolor(int color)中color的取值范圍相同。 介紹完了前面兩個(gè)問(wèn)題,現(xiàn)在來(lái)寫(xiě)一個(gè)程序。這個(gè)程序演示前了面所介紹的幾個(gè)圖形函數(shù)。 程序prog1.c 怎樣獲取鍵盤(pán)輸入? 在Tc2.0中有一個(gè)處理鍵盤(pán)輸入的函數(shù)bioskey(); int bioskey(int cmd); 當(dāng)cmd為1時(shí),bioskey()檢測(cè)是否有鍵按下。沒(méi)有鍵按下時(shí)返回0;有鍵按下時(shí)
10、返回按鍵碼(任何按鍵碼都不為0),但此時(shí)并不將檢測(cè)到的按 鍵碼從鍵盤(pán)緩沖隊(duì)列中清除。 當(dāng)cmd為0時(shí),bioskey()返回鍵盤(pán)緩沖隊(duì)列中的按鍵碼,并將此按鍵碼從鍵盤(pán)緩沖隊(duì)列中清除。如果鍵盤(pán)緩沖隊(duì)列為空,則一直等到有鍵按 下,才將得到的按鍵碼返回。 Escape鍵的按鍵碼為0x11b,下面的小程序可以獲取按鍵的按鍵碼。 for (;;) { key=bioskey(0); /* wait for a keystroke */ printf(0x%xn,key); if (key==0x11b) break; /* Escape */ } 常用按鍵的按鍵
11、碼如下: #define VK_LEFT 0x4b00 #define VK_RIGHT 0x4d00 #define VK_DOWN 0x5000 #define VK_UP 0x4800 #define VK_HOME 0x4700 #define VK_END 0x4f00 #define VK_SPACE 0x3920 #define VK_ESC 0x011b #define VK_ENTER 0x1c0d 完整的程序請(qǐng)參見(jiàn)prog2.c、prog3.c。 prog2.c獲取按鍵的按鍵碼,按Escape鍵退出程序。 prog3.c根據(jù)不同的按鍵
12、進(jìn)行不同的操作,按Escape鍵退出程序。 怎樣控制方塊的移動(dòng)? 方塊移動(dòng)的實(shí)現(xiàn)很簡(jiǎn)單,將方塊原來(lái)的位置用背景色畫(huà)一個(gè)同樣大小的方塊,將原來(lái)的方塊涂去。然后在新的位置上重新繪制方塊就可以 了。這樣就實(shí)現(xiàn)了方塊的移動(dòng)。完整的程序請(qǐng)參見(jiàn)prog4.c。這個(gè)用方向鍵控制一個(gè)黃色的小方塊在屏幕上上、下、左、右移動(dòng)。這個(gè)程序用到了前面幾個(gè)問(wèn)題講的內(nèi)容,如果你有點(diǎn)忘了,還要回頭看看哦。:) 怎樣控制時(shí)間間隔(用于游戲中控制形狀的下落)? 解決這個(gè)問(wèn)題要用到時(shí)鐘中斷。時(shí)鐘中斷大約每秒鐘發(fā)生18.2次。截獲正常的時(shí)鐘中斷后,在處理完正常的時(shí)鐘中斷后,將一個(gè)計(jì)時(shí)變量 加1。這
13、樣,每秒鐘計(jì)時(shí)變量約增加18。需要控控制時(shí)間的時(shí)候,只需要看這個(gè)計(jì)時(shí)變量就行了。 截獲時(shí)鐘中斷要用到函數(shù)getvect()和setvect()。 兩個(gè)函數(shù)的聲明如下: ?void interrupt (*getvect(int interruptno))(); ?void setvect(int interruptno, void interrupt (*isr) ( )); 保留字interrupt指示函數(shù)是一個(gè)中斷處理函數(shù)。在調(diào)用中斷處理函數(shù)的時(shí)候,所有的寄存器將會(huì)被保存。中斷處理函數(shù)的返回時(shí)的指令是iret,而不是一般函數(shù)用到的ret指令。 getve
14、ct()根據(jù)中斷號(hào)interruptno獲取中斷號(hào)為interruptno的中斷處理函數(shù)的入口地址。 setvect()將中斷號(hào)為interruptno的中斷處理函數(shù)的入口地址改為isr()函數(shù)的入口地址。即中斷發(fā)生時(shí),將調(diào)用isr()函數(shù)。 在程序開(kāi)始的時(shí)候截獲時(shí)鐘中斷,并設(shè)置新的中斷處理。在程序結(jié)束的時(shí)候,一定要記著恢復(fù)時(shí)鐘中斷哦,不然系統(tǒng)的計(jì)時(shí)功能會(huì)出問(wèn)題 的。具體演示程序請(qǐng)參見(jiàn)prog5.c。由于中斷處理大家可能用的不多,所以我把prog5.c這個(gè)程序完整地貼在下面,并加上詳細(xì)的解釋。 /* prog5.c */ This is an interrupt se
15、rvice routine. You can NOT compile this program with Test Stack Overflow turned on and get an executable file which will operate correctly. */ /* 這個(gè)程序每隔1秒鐘輸出一個(gè)整數(shù),10秒鐘后結(jié)束程序。 按escape鍵提前退出程序 。*/ #include #include #include /* Escape key */ #define VK_ESC 0x11b #define TIMER 0x1c /*
16、 時(shí)鐘中斷的中斷號(hào) */ /* 中斷處理函數(shù)在C和C++中的表示略有不同。 如果定義了_cplusplus則表示在C++環(huán)境下,否則是在C環(huán)境下。 */ #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif int TimerCounter=0; /* 計(jì)時(shí)變量,每秒鐘增加18。 */ /* 指向原來(lái)時(shí)鐘中斷處理過(guò)程入口的中斷處理函數(shù)指針(句柄) */ void interrupt ( *oldhandler)(__CPPARGS); /* 新的時(shí)鐘中斷處理函數(shù)
17、*/ void interrupt newhandler(__CPPARGS) { /* increase the global counter */ TimerCounter++; /* call the old routine */ oldhandler(); } /* 設(shè)置新的時(shí)鐘中斷處理過(guò)程 */ void SetTimer(void interrupt (*IntProc)(__CPPARGS)) { oldhandler=getvect(TIMER); disable(); /* 設(shè)置新的時(shí)鐘中斷處理過(guò)程時(shí),禁止所有中斷 */ setvect(TI
18、MER,IntProc); enable(); /* 開(kāi)啟中斷 */ } /* 恢復(fù)原有的時(shí)鐘中斷處理過(guò)程 */ void KillTimer() { disable(); setvect(TIMER,oldhandler); enable(); } void main(void) { int key,time=0; SetTimer(newhandler); /* 修改時(shí)鐘中斷 */ for (;;) { if (bioskey(1)) { key=bioskey(0); if (key==VK_ESC) /* 按escape鍵提前退
19、出程序 */ { printf(User cancel!n); break; } } if (TimerCounter>18) /* 1秒鐘處理一次 */ { /* 恢復(fù)計(jì)時(shí)變量 */ TimerCounter=0; time++; printf(%dn,time); if (time==10) /* 10秒鐘后結(jié)束程序 */ { printf(Program terminated normally!n); break; } } } KillTimer(); /* 恢復(fù)時(shí)鐘中斷 */ } 游戲中的各種形狀及整個(gè)游戲空間怎么用數(shù)據(jù)表示?
20、 以后我提到的形狀都是指下面七種形之一及它們旋轉(zhuǎn)后的變形體。 □□□□ □□□□ □□□□ □□□□ □■□□ □■■□ □□□□ □□□□ □■□□ □■□□ □■□□ □■■□ □■■□ □■□□ ■■■□ ■■□□ □□□□ □■□□ □□□□ □□□□ □■□□ □□□□ ■■□□ □■□□ □■■□ □■■□ □■□□ □■■□ 我定義了一個(gè)結(jié)構(gòu)來(lái)表示形狀。 struct shape { int xy[8]; int color; int next; } -1 0 1 2 -3□□□□ -2□□□□ -1□□□□ 0
21、□■□□ 所有的各種形狀都可以放在4x4的格子里。假定第二列,第四行的格子坐標(biāo)為(0,0)(如上圖中黑塊所示),則每個(gè)形狀的四個(gè)方塊都可以用4 個(gè)數(shù)對(duì)來(lái)表示。坐標(biāo)x從左向右依次增加,y從上到下依次增加。表示的時(shí)候,組成該形狀的四個(gè)方塊從左到右,從上到下(不一定非要按這個(gè)順 序)。如上面七種形狀的第一個(gè)用數(shù)對(duì)來(lái)表示就是(-2,0)、(-1,0)、(0,0)、(1,0)。結(jié)構(gòu)shape中的xy就是用來(lái)表示這4個(gè)數(shù)對(duì)的。為了簡(jiǎn)化程序,用一維數(shù)組xy[8]來(lái)表示。xy[0]、xy[1]表示第一個(gè)數(shù)對(duì),xy[2]、xy[3]表示第二個(gè)數(shù)對(duì),依次類推。 shape中的color表示形狀
22、的顏色,不同的形狀有不同的顏色。七種形狀及它們旋轉(zhuǎn)后的變形體一共有19種形狀,用一個(gè)全局?jǐn)?shù)組表示。假定旋轉(zhuǎn)的方向是逆時(shí)針?lè)较?順時(shí)針?lè)较虻览硪粯?。shape中的next就表示當(dāng)前形狀逆時(shí)針旋轉(zhuǎn)后的下一個(gè)形狀的序號(hào)。例如:第一種形狀及其旋 轉(zhuǎn)變形的形狀用結(jié)構(gòu)表示如下。 □□□□ □□□□ □□□□ □□□□ □■□□ □□□□ □■■□ □□□□ □■□□ □□■□ □□■□ ■■■□ □■■□ ■■■□ □□■□ ■□□□ struct shape shapes[19]= { /*{x1,y1,x2,y2,x3,y3,x4,y4, color, next}*/
23、 { 0,-2, 0,-1, 0, 0, 1, 0, CYAN, 1}, /* */ {-1, 0, 0, 0, 1,-1, 1, 0, CYAN, 2}, /* # */ { 0,-2, 1,-2, 1,-1, 1, 0, CYAN, 3}, /* # */ {-1,-1,-1, 0, 0,-1, 1,-1, CYAN, 0}, /* ## */ …… } 游戲空間指的是整個(gè)游戲主要的界面(呵呵,這個(gè)定義我實(shí)在想不出更準(zhǔn)確的,還請(qǐng)哪位大蝦指點(diǎn))。實(shí)際上是一個(gè)寬10格子、高20格子的 游戲板。用一個(gè)全局?jǐn)?shù)組board[12][22]表示。表示的時(shí)候:board[
24、x][y]為1時(shí)表示游戲板上(x,y)這個(gè)位置上已經(jīng)有方塊占著了,board[x][y] 為0表示游戲板上這位置還空著。為了便于判斷形狀的移動(dòng)是否到邊、到底,初始的時(shí)候在游戲板的兩邊各加一列,在游戲板的下面加一行,全 部填上1,表示不能移出界。即board[0][y],board[11][y](其中y從0到21)初始都為1,board[x][21](其中x從1到10)初始都為1。 1 2 3 4 5 6 7 8 910 1□□□□□□□□□□ 2□□□□□□□□□□ 3□□□□□□□□□□ 4□□□□□□□□□□ 5□□□□□□□□□□ 6□□□□□□□□□□ 7□□□□□
25、□□□□□ 8□□□□□□□□□□ 9□□□□□□□□□□ 10□□□□□□□□□□ 11□□□□□□□□□□ 12□□□□□□□□□□ 13□□□□□□□□□□ 14□□□□□□□□□□ 15□□□□□□□□□□ 16□□□□□□□□□□ 17□□□□□□□□□□ 18□□□□□□□□□□ 19□□□□□□□□□□ 20□□□□□□□□□□ prog6.c演示了用結(jié)構(gòu)表示各種形狀的方法。雖然程序稍長(zhǎng)一些,但并不是特別復(fù)雜。其中游戲板初始化部分并沒(méi)有真正用到,但是后面的程 序會(huì)用到的。其中SIZE定義為16,這樣將整個(gè)屏幕的坐標(biāo)系由原來(lái)的640480轉(zhuǎn)換
26、成4030(640/16=40,480/16=30)。游戲中所有的坐標(biāo)都是基于4030的坐標(biāo)系的,這樣有助于簡(jiǎn)化程序。坐標(biāo)的轉(zhuǎn)換在程序中由DrawBlock(int x,int y)來(lái)體現(xiàn)。 新的坐標(biāo)系如下圖所示: -8-7-6-5-4-3-2-1 0 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031 -4□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ -3□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ -2□□□□□□□□□□□□□□
27、□□□□□□□□□□□□□□□□□□□□□□□□□□ -1□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 0□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 1□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 2□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 3□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□ 4□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□ 5□□□□□□□□□■■■
28、■■■■■■■□□□■■■■□□□□□□□□□□□□□□ 6□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□ 7□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 8□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 9□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 10□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 11□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 12□□□□□□□□
29、□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 13□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 14□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 15□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 16□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 17□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 18□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 19
30、□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 20□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 21□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 22□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 23□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 24□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 25□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
31、□□□□ 26□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 新坐標(biāo)中最主要的是就是上面兩塊黑色的部分。左邊那塊大的就是游戲板(橫坐標(biāo)從1到10,縱坐標(biāo)從1到20),右邊那塊小的就是顯示“下一個(gè)”形狀的部分(橫坐標(biāo)從14到17,縱坐標(biāo)從3到6)。這個(gè)新的坐標(biāo)系是整個(gè)游戲的基礎(chǔ),后面所有的移動(dòng)、變形等的計(jì)算都是基于這個(gè)坐標(biāo)系的。 游戲中怎么判斷左右及向下移動(dòng)的可能性? 看懂了前面的各種形狀和游戲板等的表示,接下來(lái)的東西就都好辦多了。先來(lái)看一下某個(gè)形狀如何顯示在游戲板當(dāng)中。假設(shè)要在游戲板中 顯示第一個(gè)形狀。第一個(gè)形狀在結(jié)構(gòu)中的表示
32、如下: struct shape shapes[19]= { /*{x1,y1,x2,y2,x3,y3,x4,y4, color, next}*/ { 0,-2, 0,-1, 0, 0, 1, 0, CYAN, 1}, …… } 那么這個(gè)組成形狀四個(gè)方塊的坐標(biāo)表示為(0,-2)、(0,-1)、(0,0)和(1,0)。這實(shí)際上是相對(duì)坐標(biāo)。假形狀的實(shí)際坐標(biāo)指的是4x4方塊中的第 二列、第三行的方塊的位置,設(shè)這個(gè)位置為(x,y)。那么組成這個(gè)形狀的四個(gè)小方塊的實(shí)際坐標(biāo)(以第一個(gè)形狀為例)就是(x+0,y-2)、(x+0,y-1)、(x+0,y+0)和(x+1,y
33、+0)。由于所有的形狀都可以在4x4的方塊陣列中表示,這樣就找到了一種統(tǒng)一的方法來(lái)表示所有的形狀了。 -1 0 1 2 -3□□□□ 相對(duì)坐標(biāo) -2□■□□ -1□■□□ 組成第一種形狀的四個(gè)方塊的相對(duì)坐標(biāo)為(0,-2)、(0,-1)、(0,0)和(1,0)。 0□■■□ 讓我們看看形狀是如何顯示在游戲板中的(以第一個(gè)形狀為例)。 1 2 3 4 5 6 7 8 910 1□■□□□□□□□□ 形狀的坐標(biāo)為(2,3)。組成形狀的四個(gè)方塊的坐標(biāo)由形狀的 2□■□□□□□□□□ 坐標(biāo)加上這四個(gè)小方塊各自的相對(duì)坐標(biāo)得出。它們分別是: 3□■■□□□□□□□ (2+
34、0,3-2)、(2+0,3-1)、(2+0,3-0)和(2+1,3-0)。即: 4□□□□□□□□□□ (2,1)、(2,2)、(2,3)和(3,3)。如左圖所示。 5□□□□□□□□□□ 6□□□□□□□□□□ 7■□□□□□□□□□ 形狀的坐標(biāo)為(1,9)。組成形狀的四個(gè)方塊的坐標(biāo)分別是: 8■□□□□□□□□□ (1+0,9-2)、(1+0,9-1)、(1+0,9-0)和(1+1,9-0)。即: 9■■□□□□□□□□ (1,7)、(1,8)、(1,9)和(2,9)。如左圖所示。 10□□□□□□□□□□ 11□□□□□□□□□□ 12□□□□□□□□□□ 13□□□
35、□□□□□□□ 14□□□□□□□□□□ 15□□□□□□□□□□ 16□□□□□□□□□□ 17□□□□□□□□□□ 18□□□□□□□□■□ 形狀的坐標(biāo)為(9,20)。組成形狀的四個(gè)方塊的坐標(biāo)分別是: 19□□□□□□□□■□ (9+0,20-2)、(9+0,20-1)、(9+0,20-0)和(9+1,20-0)。即: 20□□□□□□□□■■ (9,18)、(9,19)、(9,20)和(10,20)。如左圖所示。 從現(xiàn)在起,我不再舉別的示例程序了。從現(xiàn)在開(kāi)始所有的示例代碼均來(lái)自于我寫(xiě)的Russia.c。為了記錄游戲板的狀態(tài),用了一個(gè)全局?jǐn)?shù)組board[12][22
36、]。board[x][y](其中x從0到11,y從1到21)等于1表示(x,y)這個(gè)位置已經(jīng)被填充了,組成形狀的四個(gè)方塊的坐標(biāo)都不能為(x,y),否則將發(fā)生沖突。board[x][y](其中x從1到10,y從1到20)等于表示(x,y)這個(gè)位置還沒(méi)有被填充。 游戲板初始化時(shí),給board[0][y],board[11][y](其中y從1到21)都賦為1,給board[x][21](其中x從1到10)都賦為1。這相當(dāng)于一開(kāi)始就給游戲板左右和下方加了個(gè)“邊”。所有的形狀都不能夠移入這個(gè)“邊”,否則將發(fā)生沖突。 現(xiàn)在我們可以開(kāi)始討論如何判斷一個(gè)形狀向左、向右和向下移動(dòng)的可能性了。
37、先說(shuō)個(gè)概念,“當(dāng)前形狀”是指那個(gè)正在下落還沒(méi)有落到底的那個(gè)形狀。如果當(dāng)前形狀向左移動(dòng),不與游戲板現(xiàn)有狀態(tài)發(fā)生沖突,則可以向左移動(dòng)。具體做法是:先假設(shè)當(dāng)前形狀已經(jīng)向左移動(dòng)了,判斷此時(shí)是否與游戲板現(xiàn)有狀態(tài)發(fā)生沖突。如果不發(fā)生沖突,則可以向左移動(dòng)。否則,不可以向左移動(dòng)。 判斷索引號(hào)為ShapeIndex的形狀在坐標(biāo)(x,y)是否與游戲板當(dāng)前狀態(tài)發(fā)生沖突的代碼如下。我把詳細(xì)的說(shuō)明加在這段代碼中。 enum bool Confilict(int ShapeIndex,int x,int y) { int i; /* 對(duì)組成索引號(hào)為ShapeIndex的形狀的四個(gè)方塊依次判斷 *
38、/ for (i=0;i<=7;i++,i++) /* i分別取0,2,4,6 */ { /* 如果四個(gè)方塊中有任何一個(gè)方塊的x坐標(biāo)小于1或大于10,表示超出左邊界或右邊界。 此時(shí),發(fā)生沖突。 */ if (shapes[ShapeIndex].xy[i]+x<1 || shapes[ShapeIndex].xy[i]+x>10) return True; /* 如果四個(gè)方塊中某個(gè)方塊的y坐標(biāo)小于1,表示整個(gè)形狀還沒(méi)有完全落入游戲板中。 此時(shí),沒(méi)有必要對(duì)這個(gè)方塊進(jìn)行判斷。*/ if (shapes[ShapeIndex].xy[i+1]+y<1) continue;
39、 /* 如果四個(gè)方塊中有任何一個(gè)方塊與游戲板當(dāng)前狀態(tài)發(fā)生沖突,則整個(gè)形狀在(x,y)處 與游戲板當(dāng)前狀態(tài)沖突 */ if (board[shapes[ShapeIndex].xy[i]+x][shapes[ShapeIndex].xy[i+1]+y]) return True; } /* 四個(gè)方塊中沒(méi)有任何一個(gè)方塊與游戲板當(dāng)前狀態(tài)發(fā)生沖突,則整個(gè)形狀在(x,y)處 沒(méi)有與游戲板當(dāng)前狀態(tài)沖突 */ return False; } 對(duì)以上代碼附加說(shuō)明如下: shapes[ShapeIndex].xy[i](其中i等于0,2,4,6)表示組成索引號(hào)為ShapeInde
40、x的形狀的某個(gè)方塊的x相對(duì)坐標(biāo)。(i等于0時(shí),表示第1個(gè)方塊的x相對(duì)坐標(biāo);i等于2時(shí),表示第2個(gè)方塊的x相對(duì)坐標(biāo);i等于4時(shí),表示第3個(gè)方塊的x相對(duì)坐標(biāo);i等于6時(shí),表示第4個(gè)方塊的x相對(duì)坐標(biāo)。) shapes[ShapeIndex].xy[i](其中i等于1,3,5,7)表示組成索引號(hào)為ShapeIndex的形狀的某個(gè)方塊的y相對(duì)坐標(biāo)。(i等于1時(shí),表示第1個(gè)方塊的y相對(duì)坐標(biāo);i等于3時(shí),表示第2個(gè)方塊的y相對(duì)坐標(biāo);i等于5時(shí),表示第3個(gè)方塊的y相對(duì)坐標(biāo);i等于7時(shí),表示第4個(gè)方塊的y相對(duì)坐標(biāo)。) shapes[ShapeIndex].xy[i]+x(其中i等于0,2,4
41、,6)表示索引號(hào)為ShapeIndex的形狀的坐標(biāo)為(x,y)時(shí),組成該形狀的某個(gè)方塊的x實(shí)際坐標(biāo)。(i等于0時(shí),表示第1個(gè)方塊的x實(shí)際坐標(biāo);i等于2時(shí),表示第2個(gè)方塊的x實(shí)際坐標(biāo);i等于4時(shí),表示第3個(gè)方塊的x實(shí)際坐標(biāo);i等于6時(shí),表示第4個(gè)方塊的x實(shí)際坐標(biāo)。) shapes[ShapeIndex].xy[i]+y(其中i等于1,3,5,7)表示索引號(hào)為ShapeIndex的形狀的坐標(biāo)為(x,y)時(shí),組成該形狀的某個(gè)方塊的y實(shí)際坐 標(biāo)。(i等于1時(shí),表示第1個(gè)方塊的y實(shí)際坐標(biāo);i等于3時(shí),表示第2個(gè)方塊的y實(shí)際坐標(biāo);i等于5時(shí),表示第3個(gè)方塊的y實(shí)際坐標(biāo);i等于7時(shí),表示第4個(gè)方
42、塊的y實(shí)際坐標(biāo)。) 現(xiàn)在來(lái)看看這句是什么意思吧。 board[shapes[ShapeIndex].xy[i]+x][shapes[ShapeIndex].xy[i+1]+y] 可以這樣理解,把上面一句分開(kāi)來(lái)看:: ActualX=shapes[ShapeIndex].xy[i]+x;/* 其中x為0,2,4,6 */ 表示某個(gè)方塊實(shí)際的x坐標(biāo)。 ActualY=[shapes[ShapeIndex].xy[i+1]+y; 表示某個(gè)方塊實(shí)際的y坐標(biāo)。 board[ActualX][ActualY]就是與某個(gè)方塊坐標(biāo)相同處的游戲板的標(biāo)志。如果此標(biāo)志不為0(為1
43、),表示這個(gè)方塊與游戲板發(fā)生沖突。如果此標(biāo)志為0,表示這個(gè)方塊沒(méi)有與游戲板發(fā)生沖突。 這段寫(xiě)的比較長(zhǎng),但是不是特別難理解。游戲中很多地方都用到了這種相對(duì)坐標(biāo)向?qū)嶋H坐標(biāo)的轉(zhuǎn)換方式,看懂了這一段對(duì)理解其他部分的代碼很有幫助。 仔細(xì)看過(guò)這段代碼后,你可能會(huì)提一個(gè)問(wèn)題:不是已經(jīng)在游戲板的左右兩邊都加了“邊”了嗎,為什么還要加下面這個(gè)對(duì)x坐標(biāo)的判斷呢? /* 如果四個(gè)方塊中有任何一個(gè)方塊的x坐標(biāo)小于1或大于10,表示超出左邊界或右邊界。 此時(shí),發(fā)生沖突。 */ if (shapes[ShapeIndex].xy[i]+x<1 || shapes[ShapeIndex].xy[
44、i]+x>10) return True; 這是因?yàn)橛幸环N特殊情況,如下圖所示: ■■ ■ 2 3 4 5 6 7 8 910 1■□□□□□□□□□ 這在當(dāng)前形狀剛出來(lái)的時(shí)候,是可能發(fā)生的。但是我們只給游戲板 2□□□□□□□□□□ 加了一層“邊”。對(duì)于這個(gè)形狀的最左邊的那個(gè)方塊將失去判斷, 3□□□□□□□□□□ 如果不予理會(huì),這個(gè)形狀將會(huì)“掛”在游戲板的左上角!當(dāng)初我也 4□□□□□□□□□□ 沒(méi)有想到這一點(diǎn),后來(lái)發(fā)現(xiàn)會(huì)有形狀“掛”在最頂層,而導(dǎo)致游戲 5□□□□□□□□□□ 提前退出。發(fā)現(xiàn)了這個(gè)問(wèn)題。 6□□□□□□□□□□ 7□□□□□□□□□□ 8□□□□□□□□□□ 加了這個(gè)判斷后,游戲板的左右兩個(gè)“邊”對(duì)沖突的判斷就是去意 9□□□□□□□□□□ 義了。因?yàn)闆](méi)有這兩個(gè)“邊”,對(duì)于沖突的判斷也不會(huì)出錯(cuò)。不過(guò) 10□□□□□□□□□□ 為了程序易于理解,還是保留了游戲板的左右兩個(gè)“邊”。 11□□□□□□□□□□ 12□□□□□□□□□□ 13□□□□□□□□□□ 14□□□□□□□□□□ 15□□□□□□□□□□ 16□□□□□□□□□□ 17□□□□□□□□□□ 18□□□□□□□□□□ 19□□□□□□□□□□ 20□□□□□□□□□□
- 溫馨提示:
1: 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 6.煤礦安全生產(chǎn)科普知識(shí)競(jìng)賽題含答案
- 2.煤礦爆破工技能鑒定試題含答案
- 3.爆破工培訓(xùn)考試試題含答案
- 2.煤礦安全監(jiān)察人員模擬考試題庫(kù)試卷含答案
- 3.金屬非金屬礦山安全管理人員(地下礦山)安全生產(chǎn)模擬考試題庫(kù)試卷含答案
- 4.煤礦特種作業(yè)人員井下電鉗工模擬考試題庫(kù)試卷含答案
- 1 煤礦安全生產(chǎn)及管理知識(shí)測(cè)試題庫(kù)及答案
- 2 各種煤礦安全考試試題含答案
- 1 煤礦安全檢查考試題
- 1 井下放炮員練習(xí)題含答案
- 2煤礦安全監(jiān)測(cè)工種技術(shù)比武題庫(kù)含解析
- 1 礦山應(yīng)急救援安全知識(shí)競(jìng)賽試題
- 1 礦井泵工考試練習(xí)題含答案
- 2煤礦爆破工考試復(fù)習(xí)題含答案
- 1 各種煤礦安全考試試題含答案