日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

解析一个C语言俄罗斯方块游戏,包你看了就会

發(fā)布時間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解析一个C语言俄罗斯方块游戏,包你看了就会 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

最近在看俄羅斯方塊的游戲,看到一個大神寫的俄羅斯方塊代碼,非常非常優(yōu)秀,拿出來解析給大家看看,也希望大家自己嘗試運行試試,從中能得到一些啟發(fā)。

#先了解下俄羅斯方塊的幾個形狀

一共分成 7 形狀,有的形狀有 4種狀態(tài),有的形狀有1種狀態(tài)。

不管是多少種狀態(tài),一個方塊需要一個2個字節(jié)來存儲,也就是16bit來保存一個方塊的信息。

基于上面的理論,我們可以使用4x4的數(shù)組來保存方塊的信息。

注意,下面代碼中的 "■" 占用的是2個字節(jié)。

#寫代碼來顯示這個方塊

方塊數(shù)據(jù),這兩個數(shù)組其實是兩種游戲模式的方塊信息,我們只需要分析一種就可以了。

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這個方塊的數(shù)據(jù)0x4859 對應(yīng)的二進制 0B0100100001011001來做個例子。

0100??---->?對應(yīng)坐標(biāo)(1,0) 1000??---->?對應(yīng)坐標(biāo)(2,0) 0101??---->?對應(yīng)坐標(biāo)(1,1) 1001??---->?對應(yīng)坐標(biāo)(2,1)

通過這個坐標(biāo),我們會輸出這樣一個方塊

再舉個例子

我們拿 Z這個方塊的數(shù)據(jù)0x0156 對應(yīng)的二進制 0B0000000101010110來做個例子。

0000??---->?對應(yīng)坐標(biāo)(0,0) 0001??---->?對應(yīng)坐標(biāo)(0,1) 0101??---->?對應(yīng)坐標(biāo)(1,1) 0110??---->?對應(yīng)坐標(biāo)(1,2)

顯示方塊沒有問題了

上面的代碼中,如果mode等于0的話,也就是把某個方塊從顯示中擦除掉。

我們用devc++寫的程序,需要知道幾個細(xì)節(jié)。

#構(gòu)建固定行列的窗口

正常情況,我們顯示cmd是一個默認(rèn)值的黑框「如下圖」。

實際上,我們可以用代碼來固定cmd的框框大小。

默認(rèn)代碼輸出

示例代碼:

#include???<conio.h> #include???<stdio.h> #include??<stdlib.h> #include????<time.h> #include?<Windows.h>/**********Main主函數(shù)***********/ int?main() {system("color?F1&mode?con?cols=35?lines=25");getchar();return?0; }

程序輸出:

#延遲函數(shù)的設(shè)計

跟其他不同的是,這個程序的延遲沒有使用usleep,我覺得這也是非常值得稱贊的地方,不過空跑cpu,哈哈,是有那么一點調(diào)皮。

把延遲放到鍵值獲取的函數(shù)中。

/**********按鍵獲取**************/ 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>/**********初始化參數(shù)************/ 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}};/**********光標(biāo)位置函數(shù)**********/ 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; }/***********塊體轉(zhuǎn)置*************/ 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() {//~~~游戲結(jié)束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;}//~~~關(guān)卡得分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? /***********循環(huán)核心*************/ 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主函數(shù)***********/ int?main() {system("color?F0&mode?con?cols=35?lines=25");HideCursor();CreatUI();GameCycle(10,800,1);return?0; }

#后記

里面涉及的很多東西,我都沒有完全總結(jié)出來,作者的巧妙非常令我佩服,后面應(yīng)該還會有文章分析。

大家有什么想法或者自己的解讀,可以留言,歡迎一起討論,共同進步,探索代碼里面的奧秘和樂趣。

方塊消除

準(zhǔn)備下一個方塊

得分機制

Game Over 判斷

推薦閱讀:

專輯|Linux文章匯總

專輯|程序人生

專輯|C語言

我的知識小密圈

總結(jié)

以上是生活随笔為你收集整理的解析一个C语言俄罗斯方块游戏,包你看了就会的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。