解析一个C语言俄罗斯方块游戏,包你看了就会
最近在看俄羅斯方塊的游戲,看到一個大神寫的俄羅斯方塊代碼,非常非常優秀,拿出來解析給大家看看,也希望大家自己嘗試運行試試,從中能得到一些啟發。
#先了解下俄羅斯方塊的幾個形狀
一共分成 7 形狀,有的形狀有 4種狀態,有的形狀有1種狀態。
不管是多少種狀態,一個方塊需要一個2個字節來存儲,也就是16bit來保存一個方塊的信息。
基于上面的理論,我們可以使用4x4的數組來保存方塊的信息。
注意,下面代碼中的 "■" 占用的是2個字節。
#寫代碼來顯示這個方塊
方塊數據,這兩個數組其實是兩種游戲模式的方塊信息,我們只需要分析一種就可以了。
int?TGM[7][4]={{0x159D,0x89AB,0x159D,0x89AB},{0x126A,0x4856,0x159A,0x4526},{0x926A,0x456A,0x1592,0x0456},{0x4859,0x4859,0x4859,0x4859},{0x5926,0x0156,0x5926,0x0156},{0x4159,0x4596,0x1596,0x4156},{0x156A,0x4152,0x156A,0x4152}}; int?SRS[7][4]={{0x159D,0x89AB,0x26AE,0x4567},{0x0159,0x4856,0x159A,0x4526},{0x8159,0x456A,0x1592,0x0456},{0x4859,0x4859,0x4859,0x4859},{0x4815,0x459A,0x5926,0x0156},{0x4159,0x4596,0x1596,0x4156},{0x0459,0x8596,0x156A,0x4152}};我們分析這段代碼
/***********擦除顯示*************/ int?Display(int?x,?int?y,?int?CAC,?int?Mode) {for(j=0;j<=3;j++){P[j]=CAC&0xF,?CAC>>=4;if?????(Mode==1){Pos((P[j]>>2)+x,(P[j]&0x3)+y);printf("■");}else?if(Mode==0){Pos((P[j]>>2)+x,(P[j]&0x3)+y);printf("?");}}return?0; }P[j]=CAC&0xF 取到的是 4個bit,然后通過判斷這 4個bit決定輸出方塊的位置。
我們拿 0這個方塊的數據0x4859 對應的二進制 0B0100100001011001來做個例子。
0100??---->?對應坐標(1,0) 1000??---->?對應坐標(2,0) 0101??---->?對應坐標(1,1) 1001??---->?對應坐標(2,1)通過這個坐標,我們會輸出這樣一個方塊
再舉個例子
我們拿 Z這個方塊的數據0x0156 對應的二進制 0B0000000101010110來做個例子。
0000??---->?對應坐標(0,0) 0001??---->?對應坐標(0,1) 0101??---->?對應坐標(1,1) 0110??---->?對應坐標(1,2)顯示方塊沒有問題了
上面的代碼中,如果mode等于0的話,也就是把某個方塊從顯示中擦除掉。
我們用devc++寫的程序,需要知道幾個細節。
#構建固定行列的窗口
正常情況,我們顯示cmd是一個默認值的黑框「如下圖」。
實際上,我們可以用代碼來固定cmd的框框大小。
默認代碼輸出
示例代碼:
#include???<conio.h> #include???<stdio.h> #include??<stdlib.h> #include????<time.h> #include?<Windows.h>/**********Main主函數***********/ int?main() {system("color?F1&mode?con?cols=35?lines=25");getchar();return?0; }程序輸出:
#延遲函數的設計
跟其他不同的是,這個程序的延遲沒有使用usleep,我覺得這也是非常值得稱贊的地方,不過空跑cpu,哈哈,是有那么一點調皮。
把延遲放到鍵值獲取的函數中。
/**********按鍵獲取**************/ int?Getkey(int?N,int?T) {int?start=clock();if(KEY_V==115){return?115;}do{if(kbhit()){KEY_V=(int)(getch());if(KEY_V<97){KEY_V+=32;}return?KEY_V;}for(i=0;i<=N;i++);}while((clock()-start)<T);dy=1;return?-1; }就先簡單講解下這些,至于得分機制,碰撞檢測,消除的代碼,還沒有想好怎么講明白,需要再花時間剖析剖析。
#試玩一下
#源碼
#include???<conio.h> #include???<stdio.h> #include??<stdlib.h> #include????<time.h> #include?<Windows.h>/**********初始化參數************/ int?i,j,N,T,F,J,X,Y,dx,dy,??KEY_V,??Cache1,Cache2,NU,NI,RU,RI,??P_X,P_Y,POS_H_MAX,??LEVEL=1,SCORE=0,??P[4],??POINT_V[12][22],??MARK[21],??FLAG[5]={0,0,0,1,0}; int?TGM[7][4]={{0x159D,0x89AB,0x159D,0x89AB},{0x126A,0x4856,0x159A,0x4526},{0x926A,0x456A,0x1592,0x0456},{0x4859,0x4859,0x4859,0x4859},{0x5926,0x0156,0x5926,0x0156},{0x4159,0x4596,0x1596,0x4156},{0x156A,0x4152,0x156A,0x4152}}; int?SRS[7][4]={{0x159D,0x89AB,0x26AE,0x4567},{0x0159,0x4856,0x159A,0x4526},{0x8159,0x456A,0x1592,0x0456},{0x4859,0x4859,0x4859,0x4859},{0x4815,0x459A,0x5926,0x0156},{0x4159,0x4596,0x1596,0x4156},{0x0459,0x8596,0x156A,0x4152}};/**********光標位置函數**********/ void?Pos(int?x,int?y) {COORD?pos;HANDLE?hOutput;pos.X=2*x;pos.Y=y;hOutput=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOutput,pos); }void?HideCursor() {CONSOLE_CURSOR_INFO?cursor_info={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info); }/**********初始化界面************/ void?CreatUI() {int?i,j,BOUNDARY;printf("┏━━━━━━━━━━┓\n");for(j=1;j<=20;j++)?{if?????(j==3){printf("┃??????????┃LEVEL:1\n");}else?if(j==5){printf("┃??????????┃SCORE:0\n");}else?if(j==7){printf("┃??????????┃NEXT???\n");}else?????????{printf("┃??????????┃\n");}}printf("┗━━━━━━━━━━┛\n");printf("?CopyRight@2016~2018?BY?HAPPY\n");for(j=1;j<=21;j++){for(i=0;i<=11;i++){BOUNDARY=i*(i-11)*(j-21);if(BOUNDARY==0){POINT_V[i][j]=1;}else{POINT_V[i][j]=0;}????????????????}} }/**********按鍵獲取**************/ int?Getkey(int?N,int?T) {int?start=clock();if(KEY_V==115){return?115;}do{if(kbhit()){KEY_V=(int)(getch());if(KEY_V<97){KEY_V+=32;}return?KEY_V;}for(i=0;i<=N;i++);printf("%d\n",clock()-start);}while((clock()-start)<T);dy=1;return?-1; }/***********塊體轉置*************/ int?Rote(int?S,?int?I) {return?(F==0)?TGM[S][(I+4)%4]:SRS[S][(I+4)%4]; }/***********擦除顯示*************/ int?Display(int?x,?int?y,?int?CAC,?int?Mode) {for(j=0;j<=3;j++){P[j]=CAC&0xF,?CAC>>=4;if?????(Mode==1){Pos((P[j]>>2)+x,(P[j]&0x3)+y);printf("■");}else?if(Mode==0){Pos((P[j]>>2)+x,(P[j]&0x3)+y);printf("?");}}return?0; }/***********固化塊體*************/ int?DoBlocks() {//~~~游戲結束if(Y<2){Pos(1,22);printf("GAME OVER!");exit(0);}//~~~固化塊體POS_H_MAX=0,?FLAG[3]=1;for(j=0;j<=3;j++){P_X=(P[j]>>2)+X,P_Y=(P[j]&0x3)+Y;if(POS_H_MAX<P_Y){POS_H_MAX=P_Y;}POINT_V[P_X][P_Y]=1;}//~~~關卡得分for(j=Y;j<=POS_H_MAX;j++){FLAG[2]=1;for(i=1;i<=10;i++){if(POINT_V[i][j]==0){FLAG[2]=0;}}if(FLAG[2]){SCORE+=10,MARK[j]=1;if(SCORE==400){SCORE=0,LEVEL+=1,T-=100;FLAG[4]=1;????????}}}//~~~極品消行for(j=20;j>=5;j--){if(FLAG[4]){for(i=1;i<=10;i++){POINT_V[i][j]=0;Pos(i,j);printf("?");}}else?if(MARK[j]){MARK[j]=0,J=j-1;for(N=1;N<=3;N++){if(MARK[J]){J--;}}MARK[J]=1;for(i=1;i<=10;i++){Pos(i,j);if(POINT_V[i][j]=POINT_V[i][J]){printf("■");}else{printf("?");}}}}FLAG[4]=0;return?0; }/***********碰撞檢測*************/ int?CheckCollision() {????????????????????????????????for(j=0;j<=3;j++){P_X=(P[j]>>2)+X+dx,P_Y=(P[j]&0x3)+Y+dy;if(POINT_V[P_X][P_Y]){if(dx!=0){return?1;}if(dy){DoBlocks();Pos(12,3);printf("LEVEL:%-3d",LEVEL);Pos(12,5);printf("SCORE:%-3d",SCORE);return?2;}if(KEY_V==119){FLAG[0]=1;}}}return?0; } unsigned? /***********循環核心*************/ int?GameCycle(int?N,?int?T,?int?F) {srand((unsigned)time(NULL));RU=rand()%7,RI=(rand()%4);while(1){if(FLAG[3]){Display(12,8,Rote(RU,RI),0);X=4,Y=1,?NU=RU,NI=RI,?RU=rand()%7,RI=(rand()%4),?FLAG[3]=0,KEY_V=0;Display(12,8,Rote(RU,RI),1);Display(X,?Y,Rote(NU,NI),1);}dx=0,dy=0;????????KEY_V=Getkey(N,T);if(KEY_V==119){NI++;Display(X,Y,Rote(NU,NI),2);}//旋Welse?if(KEY_V==115){dy=?1;}//下Selse?if(KEY_V==97?){dx=-1;}//左Aelse?if(KEY_V==100){dx=?1;}//右Delse?if(KEY_V==112){getch();?}//暫停Pelse?if(KEY_V==113){return?0;}//退出Qif(dx!=0?||?dy!=0?||?KEY_V==119){if(!CheckCollision()){if(FLAG[0]){NI--,FLAG[0]=0;Display(X,Y,Rote(NU,NI),0);}else?if(KEY_V==119){Display(X,Y,Rote(NU,NI-1),0);}else{Display(X,Y,Rote(NU,NI),0);}Display(X+dx,Y+dy,Rote(NU,NI),1);X+=dx,Y+=dy;}}}return?0; }/**********Main主函數***********/ int?main() {system("color?F0&mode?con?cols=35?lines=25");HideCursor();CreatUI();GameCycle(10,800,1);return?0; }#后記
里面涉及的很多東西,我都沒有完全總結出來,作者的巧妙非常令我佩服,后面應該還會有文章分析。
大家有什么想法或者自己的解讀,可以留言,歡迎一起討論,共同進步,探索代碼里面的奧秘和樂趣。
方塊消除
準備下一個方塊
得分機制
Game Over 判斷
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識小密圈
總結
以上是生活随笔為你收集整理的解析一个C语言俄罗斯方块游戏,包你看了就会的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python项目实例-实例分享 | 4个
- 下一篇: 1.5 万字 + 40 张图解 HTTP