俄罗斯方块c 代码解析(c 小游戏编程100例)

俄罗斯方块c  代码解析(c  小游戏编程100例)

#先了解下俄罗斯方块的几个形状

一共分成7形状,有的形状有4种状态,有的形状有1种状态。

不管是多少种状态,一个方块需要一个2个字节来存储,也就是16bit来保存一个方块的信息。

基于上面的理论,我们可以使用4×4的数组来保存方块的信息。

注意,下面代码中的”■”占用的是2个字节。

#写代码来显示这个方块

方块数据,这两个数组其实是两种游戏模式的方块信息,我们只需要分析一种就可以了。

intTGM[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}};intSRS[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}};

我们分析这段代码

/***********擦除显示*************/intDisplay(intx,inty,intCAC,intMode){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(“■”);}elseif(Mode==0){Pos((P[j]>>2) x,(P[j]&0x3) y);printf(“”);}}return0;}

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主函数***********/intmain(){system(“colorF1&modeconcols=35lines=25”);getchar();return0;}

程序输出:

#延迟函数的设计

跟其他不同的是,这个程序的延迟没有使用usleep,我觉得这也是非常值得称赞的地方,不过空跑cpu,哈哈,是有那么一点调皮。

把延迟放到键值获取的函数中。

/**********按键获取**************/intGetkey(intN,intT){intstart=clock();if(KEY_V==115){return115;}do{if(kbhit()){KEY_V=(int)(getch());if(KEY_V<97){KEY_V =32;}returnKEY_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>/**********初始化参数************/inti,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};intTGM[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}};intSRS[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}};/**********光标位置函数**********/voidPos(intx,inty){COORDpos;HANDLEhOutput;pos.X=2*x;pos.Y=y;hOutput=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(hOutput,pos);}voidHideCursor(){CONSOLE_CURSOR_INFOcursor_info={1,0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);}/**********初始化界面************/voidCreatUI(){inti,j,BOUNDARY;printf(“┏━━━━━━━━━━┓\n”);for(j=1;j<=20;j ){if(j==3){printf(“┃┃LEVEL:1\n”);}elseif(j==5){printf(“┃┃SCORE:0\n”);}elseif(j==7){printf(“┃┃NEXT\n”);}else{printf(“┃┃\n”);}}printf(“┗━━━━━━━━━━┛\n”);printf(“CopyRight@2016~2018BYHAPPY\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;}}}}/**********按键获取**************/intGetkey(intN,intT){intstart=clock();if(KEY_V==115){return115;}do{if(kbhit()){KEY_V=(int)(getch());if(KEY_V<97){KEY_V =32;}returnKEY_V;}for(i=0;i<=N;i );printf(“%d\n”,clock()-start);}while((clock()-start)<T);dy=1;return-1;}/***********块体转置*************/intRote(intS,intI){return(F==0)?TGM[S][(I 4)%4]:SRS[S][(I 4)%4];}/***********擦除显示*************/intDisplay(intx,inty,intCAC,intMode){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(“■”);}elseif(Mode==0){Pos((P[j]>>2) x,(P[j]&0x3) y);printf(“”);}}return0;}/***********固化块体*************/intDoBlocks(){//~~~游戏结束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(“”);}}elseif(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;return0;}/***********碰撞检测*************/intCheckCollision(){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){return1;}if(dy){DoBlocks();Pos(12,3);printf(“LEVEL:%-3d”,LEVEL);Pos(12,5);printf(“SCORE:%-3d”,SCORE);return2;}if(KEY_V==119){FLAG[0]=1;}}}return0;}unsigned/***********循环核心*************/intGameCycle(intN,intT,intF){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);}//旋Welseif(KEY_V==115){dy=1;}//下Selseif(KEY_V==97){dx=-1;}//左Aelseif(KEY_V==100){dx=1;}//右Delseif(KEY_V==112){getch();}//暂停Pelseif(KEY_V==113){return0;}//退出Qif(dx!=0||dy!=0||KEY_V==119){if(!CheckCollision()){if(FLAG[0]){NI–,FLAG[0]=0;Display(X,Y,Rote(NU,NI),0);}elseif(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;}}}return0;}/**********Main主函数***********/intmain(){system(“colorF0&modeconcols=35lines=25”);HideCursor();CreatUI();GameCycle(10,800,1);return0;}#后记

大家有什么想法或者自己的解读,可以留言,欢迎一起讨论,共同进步,探索代码里面的奥秘和乐趣。

方块消除

准备下一个方块

得分机制

Game Over 判断

– END –

推荐阅读:

C语言能够被替换吗?

四种最令人讨厌的编程语言:Java、Javascript、C 和Perl

C 语言怎么可能被淘汰呢?

每日打卡赢积分兑换书籍入口

发表评论

登录后才能评论