最近在看俄罗斯方块的游戏,看到一个大神写的俄罗斯方块代码,非常非常优秀,拿出来解析给大家看看,也希望大家自己尝试运行试试,从中能得到一些启发。

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

一共分成 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语言俄罗斯方块游戏,包你看了就会相关推荐

  1. c语言俄罗斯方块程序设计论文,c语言俄罗斯方块游戏程序设计报告

    c语言俄罗斯方块游戏程序设计报告 俄罗斯方块程序设计报告 2018-7-1511 计本(2)班 卢文俊C 语言课程设计报告主标题: C 语言课程设计 副标题: 俄罗斯方块游戏 ----界面设计姓 名: ...

  2. c语言min函数_C语言探索之旅 | 第一部分第十课:第一个C语言小游戏

    内容简介 前言 准备工作和建议 我的代码 改进方案 第一部分第十一课预告 1. 前言 上一课是 C语言探索之旅 | 第一部分第九课:循环语句 . 经过前面这么多课的努力,我们终于迎来了第一个比较正式的 ...

  3. c语言小游戏vc,C语言探索之旅:第一个C语言小游戏

    C语言探索之旅:第一个C语言小游戏-1.jpg (37.05 KB, 下载次数: 0) 2018-10-8 19:23 上传 内容简介 1.课程纲领 2.第一部分第八课:第一个C语言小游戏 3.第一部 ...

  4. 我的第一个C语言小游戏

    文章目录 前言 一.我的小介绍 二.解决问题 目前还未解决的问题 三.代码如下 前言 一.我的小介绍 大家好,我是一位大一小白,之前并没有想到我会和编程打交道,接触C语言后,我才发现C语言如此有趣,今 ...

  5. c语言俄罗斯方块游戏代码

    #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/time.h ...

  6. 俄罗斯方块游戏(C语言)

    简介:俄罗斯方块(Tetris)是一款经典的游戏,下面是用C语言实现俄罗斯方块的示例代码: code #include <stdio.h> #include <stdlib.h> ...

  7. python俄罗斯方块算法详解_用 Python 写一个俄罗斯方块游戏 (

    @@ -2,34 +2,34 @@ > * 原文作者:[Dr Pommes](https://medium.com/@pommes) > * 译文出自:[掘金翻译计划](https://g ...

  8. Python 写一个俄罗斯方块游戏

    使用 Python 的 PyGame 库写一个俄罗斯方块游戏的逐步指南 很多人学习python,不知道从何学起. 很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. 很多已经做案例 ...

  9. 用 Python 写一个俄罗斯方块游戏

    使用 Python 的 PyGame 库写一个俄罗斯方块游戏的逐步指南 在这篇教程中,我们会用 Python 的 PyGame 库写一个简单的俄罗斯方块游戏.里面的算法很简单,但对新手可能有一点挑战性 ...

最新文章

  1. python实例 列表
  2. 用新语法写更简洁的ABAP代码
  3. Delphi10 安装Graphics32
  4. 树状数组的相关知识 及 求逆序对的运用
  5. SU sunmo命令学习
  6. 数据库事物用法 SET XACT_ABORT ON
  7. SUID、SGID、粘滞位
  8. 最容易理解的handler
  9. 【推荐系统】16篇最新推荐系统论文送你
  10. oracle 的控制结构
  11. 网络狂飙(netspeeder) v3.80 简体中文版 下载
  12. 测试经验 --- 那些躲在角落的缺陷
  13. 使用工具清理Windows的winsxs目录
  14. 七色的寒冷彩虹便冒了出来
  15. OSChina 周五乱弹 —— duang ~ duang ~ duang~
  16. javascript错误:对象不支持此属性或方法
  17. 哔哩哔哩 2019秋招编程题---山寨金闪闪
  18. 高防CDN如何防御网络攻击
  19. 夏季湿盛是什么意思,湿盛有哪些表现?
  20. html代码演讲,index.html

热门文章

  1. Strus2中关于ValueStack详解
  2. SQL Server有这些属性吗
  3. 有关Accordion组件的研究——Silverlight学习笔记[27]
  4. 配置u-boot的ip、网卡ip的命令
  5. 一对一 一对多 多对多
  6. java uuid 线程安全_java – 在多线程应用程序中生成相同的UUID
  7. 清华大学《操作系统》(七):虚拟存储、覆盖、交换
  8. tornado学习笔记day03-响应输出
  9. 解决 Cannot open D:\Program Files\Anaconda3\Scripts\pip-script.py 问题
  10. DLL导出类和导出函数