编程项目实战:解析一个C语言俄罗斯方块游戏,图文+代码透析
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了编程项目实战:解析一个C语言俄罗斯方块游戏,图文+代码透析,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含10387字,纯文字阅读大概需要15分钟。
内容图文
![编程项目实战:解析一个C语言俄罗斯方块游戏,图文+代码透析](/upload/InfoBanner/zyjiaocheng/607/9e7d6f2f8ae74a279365810b07ca7197.jpg)
以下文章来源于嵌入式Linux ,作者写代码的篮球球痴
最近在看俄罗斯方块的游戏,看到一个大神写的俄罗斯方块代码,非常非常优秀,拿出来解析给大家看看,也希望大家自己尝试运行试试,从中能得到一些启发。
#先了解下俄罗斯方块的几个形状
一共分成 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);
????????????????}//旋W
????????????????else?if(KEY_V==115){dy=?1;}//下S
????????????????else?if(KEY_V==97?){dx=-1;}//左A
????????????????else?if(KEY_V==100){dx=?1;}//右D
????????????????else?if(KEY_V==112){getch();?}//暂停P
????????????????else?if(KEY_V==113){return?0;}//退出Q
????????????????if(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 判断
C语言是每个想要学习编程的小伙伴首要学习的语言~
如果你也想成为程序员(媛),想要快速掌握编程,这里为你分享一个学习基地!【点我进入】
里面有资深专业软件开发工程师,在线解答你的所有疑惑~C语言入门“so easy”
资料包含:编程入门、游戏编程、课程设计、黑客等。
内容总结
以上是互联网集市为您收集整理的编程项目实战:解析一个C语言俄罗斯方块游戏,图文+代码透析全部内容,希望文章能够帮你解决编程项目实战:解析一个C语言俄罗斯方块游戏,图文+代码透析所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。