为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

俄罗斯方块c语言详解

2017-09-30 50页 doc 154KB 21阅读

用户头像

is_037433

暂无简介

举报
俄罗斯方块c语言详解俄罗斯方块c语言详解 俄罗斯方块最详解 做每一件事前,都会有一个粗略的构想。编程更应该这样,现在先说一些大的、粗略的东西。 **************************************************************************************** **************************************************************************************** 目录: ?屏幕的划分 ?图形显示 ?三...
俄罗斯方块c语言详解
俄罗斯方块c语言详解 俄罗斯方块最详解 做每一件事前,都会有一个粗略的构想。编程更应该这样,现在先说一些大的、粗略的东西。 **************************************************************************************** **************************************************************************************** 目录: ?屏幕的划分 ?图形显示 ?三种坐标。 绝对坐标、相对坐标、左上角坐标 ?方块的构造 ?动画效果 ?键盘控制 ?判断方块碰撞 ?消行 ?变形 ?关于菜单的制作 ?附录(完整的源程序) **************************************************************************************** **************************************************************************************** 1、屏幕的划分 将整个屏幕划分成四部分:a、一个没盖的杯子;b、一个不断下落4*4数组的盒子;c、一个给 预览下一个方块4*4数组的盒子;d、提示信息。由于提示信息比较简单,这里只讨论前三样。 没盖的杯子: 即平时说玩这款游戏时,下落方块不可超出的那个边界,下落的方块从这个“杯口”的上方往下下落,方块只在“杯子”里移动、变形、停止。 游戏空间指的是整个游戏主要的界面(呵呵,其实就是所说的“杯子”)。实际上是一个宽10格子、高20格子的 游戏板。用一个全局数组GameSpace[22][12]表示。表示的时候:GameSpace[x][y]为1时表示游戏板上(x,y)这个位置上已经有方块占着了,GameSpace[x][y]为0表示游戏板上这位置还空着。为了便于判 断形状的移动是否到边、到底,初始的时候在游戏板的两边各加一列,在游戏板的下面加一行,全 部填上 1,表示不能移出界。即GameSpace[x][0],GameSpace[x][11](其中x从0到20)初始都为1,GameSpac e[20][y](其中y从0到11)初始都为1。 0 1 2 3 4 5 6 7 8 910 0???????????? 1???????????? 2???????????? 3???????????? 4???????????? 5???????????? 6???????????? 7???????????? 8???????????? 9???????????? 10???????????? 11???????????? 12???????????? 13???????????? 14???????????? 15???????????? 16???????????? 17???????????? 18???????????? 19???????????? 20???????????? 下落的4*4盒子: 即7种的方块形状,如我认为比较经典的测试方块“7字形” 可看作: 0 1 2 3 0???? {{0,0,0,0}, 1???? 用数组表示则是 {0,1,1,0}, 2???? {0,0,1,0}, 3???? {0,0,1,0}} 预览4*4数组盒子: 即玩这款游戏时,给看下一个方块是什么样的窗口。 这三样东西可以这样联系起来:一个不断下落的盒子由杯子的上方下落到杯子底部,之后将预览盒子的东西放到下落的4*4盒子中,如此循环反复…… 2、图形显示 Tc2.0中有两种显示模式,一种是我们所熟知的字符模式,另一种是图形模式。在字符模式下只能显式字符,如ASCII字符。一般是显示25 行,每行80个字符。程序缺省的是字符模式。在字符模式下不能显式图形和进行绘图操作。要想进行图形显示和绘图操作,必须切换到图形模 式下。 Tc2.0中用initgraph()函数可以切换到图形模式,用closegraph()可以从图形模式切换回字符模式。initgraph()和closegraph()都是图形 函数,使用图形函数必须包括头文件"graphics.h"。 void far initgraph(int far *graphdriver,int far *graphmode,char far *pathtodriver);graphdriver是上涨指向图形驱动序号变量的指针;graphmode是在graphdriver选定后,指向图形显示模式序号变量的指针。pathtodriver表示存放图形驱动文件的路径。 特别值得一提的是驱动文件路径的写法,由于有转义字符,如bgi文件夹(一般这个文件夹就在Tc文件夹目录下,这个说明文档黙认bgi在c:\,后面举的例子亦然)在c:\,写的时候很多人写成"c:\bgi",少了个\,应写成"c:\\bgi",切记。 此外,我还强烈建议借一本叫《c作图与c汉字技术》的,这是我见过介绍c 绘图方面最全面的书了, 为了节省时间,可以直接看这几个函数,这些函数均包含在头文件#include 中 void line( int x,int y,int xx,int yy); /*从(x,y)到(xx,yy)处以setcolor()决定的颜色画直线*/ void setlinestyle(int linestyle , unsigned upattern ,int thickness ); /*linestyle 变化范围为 0 ~ 4,也可以是大写的英文*/ /*分别表示实线,点线,中心线,点画线,用户自定义线*/ /*upattern处一般写0*/ /*thickness只有1、3两个值,分别表示一个像素宽,三个像素宽*/ void setcolor (int color ); /*决定前景颜色,color 变化范围为 0 ~ 15也可以是大写的英文*/ void setbkcolor(int color); /*决定背景颜色,color 变化范围为 0 ~ 15也可以是大写的英文*/ void rectangle(int x,int y,int xx,int yy);/*以(x,y)为左上角,以(xx,yy)为右下角画矩形*/ void bar(int x,int y,int xx,int yy); /*以(x,y)为左上角,以(xx,yy)为右下角画条形*/ void bar3d(int x,int y,int xx,int yy,int depth,int topflag); /*以(x,y)为左上角,以(xx,yy)为右下角画立体条形*/ /*depth决定了三维直方图的长度*/ /*当topflag非0时,画出三维顶,否则不画出三维顶*/ void setfillstyle(int pattern,int color);/*pattern变化范围为 0 ~ 12也可以是大写的英文*/ /*color 变化范围为 0 ~ 15也可以是大写的英文*/ char* itoa(int n,char* str,int radix); /*n是要转的整型变量 */ /*str用来存的字符串*/ /*radix是按什么进制转化*/ /*能将整型数字转成字符型数字,结合outtextxy()*/ /*可将得分、菜单上的数值等简单地显示在屏幕上*/ void settextjustify(int horiz,int vert); /*horiz变化范围为 0 ~ 2,也可以是大写的英文,分别代表左对齐,字符串中心对齐,右对齐*/ /*vert 变化范围为 0 ~ 2,也可以是大写的英文,分别代表底部对齐,中心对齐,顶部对齐*/ void settextstyle(int font,int direction,int charsize); /*font变化范围为 0 ~ 12也可以是大写的英文*/ /*direction只能是0、1,也可以是大写的英文,0、1分别代表水平输出,垂直输出*/ /*charsize变化范围为 1 ~ 10也可以是大写的英文,数值越大,字体越大*/ void outtextxy(int x,int y,char* str); /*按settextjustify()决定的对齐方式*/ /*以setcolor()决定的颜色,在(x,y)附近输出字符串*/ (在第10点的小程序中有以上的大部分函数的实现) 3、三种坐标。 绝对坐标、相对坐标、左上角坐标 绝对坐标: 图形屏幕其实是个y轴的正方向朝下,原点在屏幕最左上角的直角坐标系,vga模式下的一般分辨率为640*480,这样就把屏幕横向、纵向分别平分640等分、480等分,横、纵坐标变化范围分别为0 ~ 639,0 ~ 479,每个像素点占用一个1的长度。我们说的绝对坐标就是以屏幕原点为相对点的切切实实的坐标。 相对坐标: 即以屏幕上某个绝对坐标为相对点(或把它看成原点),在这个基础上再计算的坐标。 如以(0,0)为相对点,(1,1)的绝对坐标为(1,1),相对坐标为(1,1);以(2,2)相对点,(1,1)的绝对坐标为(1,1),相对坐标为(-1,-1)。 左上角坐标: 特别提出这个,是因为在俄罗斯方块中解决数组与屏幕连接的关健所在。如画个小正方形时用函数rectangle(x,y,x+单位长度,y+单位长度) (其中(x,y)为这个正方形的左上角坐标,单位长度可以是10,16,我就取了16,这样在640*480中便变成了 (640/16)*(480/16) = 40*30 ),又如前面说的GameSpace[21][12]可以这样化散为整成GameSpace[(x-相对原点的x)/单位长度][(y-相对原点的y)/单位长度]。 4、方块的构造 为了简单处理,我选择了数组构造方块,而不是坐标描点,但这样浪费空间。在要画的地方赋1,不画的地方赋0,如长条可表示为 0 1 2 3 0???? {{0,1,0,0}, 到了这里,我们应 ____ 1???? 用数组表示则是 {0,1,0,0}, 已深入的将各种方 ?? 2???? {0,1,0,0}, 块看成由四个小正 | | 看成 ? 3???? {0,1,0,0}} 形组成,如 |_| ? 为突出立体感,可以在画了一个小正方形后,再用line()函数在这个小正方形的左上角坐标附近画横、纵两条白线,再在小正方形的右侧画一条黒线,如图是放大的小正方形 ________ | ______ | (其中,里面的横线为白,里面左侧的纵线为白,里面右侧的纵线为黒) || || || || || || |________| 在我的程序里就没搞立体感,只为体现算法而已。 现在,整个屏幕在我们眼里应达到这样理性的看法: ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? 其中每个小正方形放大看为 ??????????????????????????????? ??????????????????????????????? (x,y)______ ??????????????????????????????? | | ??????????????????????????????? | | ??????????????????????????????? | | ??????????????????????????????? |_______| ??????????????????????????????? ??????????????????????????????? (x,y)为左上角坐标 ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? ??????????????????????????????? 5、动画效果 说穿了就是先画一个图形显示出来,延时一小段时间认人看清楚后,再将显示的图形在原来的位置涂黒(或涂成背景颜色)。其中延时函数为delay (数值),包含在头文件#include 中。 括号中的数值越大,延时越长,数值最大为65535,可配合for 循环让delay()超过65535这个数,下面给出的小程序是熟悉这个函数的.功能是一个红色的正方形斜斜地移动 /*animation.c*/ #include #include /*delay()函数的头文件*/ void main() { int gr = DETECT , gm = 0; int x = 50 , y = 50; int i , j; initgraph( &gr , &gm , "c:\\bgi" ) ; for( i = 0 ; i < 8 ; ++ i , x += 50 , y += 50) { setfillstyle( SOLID_FILL , RED ); bar( x , y , x + 50 , y + 50 ); for (j = 0 ; j < 30 ; ++ j) delay( 10000 ); /*不同的编译器显示的快慢不同,10000这个数值可根据不同的编译器改*/ setfillstyle( SOLID_FILL , BLACK ); bar( x , y , x + 50 , y + 50 ); } } 6、键盘控制 键盘上的每个键都有自己的键盘码,为了得到想要的,下面介绍一个函数 在Tc2.0中有一个处理键盘输入的函数bioskey(); int bioskey(int cmd); 当cmd为1时,bioskey()检测是否有键按下。没有键按下时返回0;有键按下时返回键盘码(任何键盘 码都不为0),但此时并不将检测到的按 键码从键盘缓冲队列中清除。 当cmd为0时,bioskey()返回键盘缓冲队列中的键盘码,并将此按键码从键盘缓冲队列中清除。如果 键盘缓冲队列为空,则一直等到有键按下,才将得到的键盘码返回。 Escape键的按键码为0x11b,下面的小程序可以获取按键的键盘码 /*keyboard_code.c*/ #include #include void main() { int key ; while ( 1 ) { key = bi oskey( 0 ); /* wait for a keystrike */ printf ( "0x%x\n" , key ); if ( key == 0x11b ) break; /* Escape */ } } 常用按键的按键码如下: #define LEFT 0x4b00 #define RIGHT 0x4d00 #define DOWN 0x5000 #define UP 0x4800 #define HOME 0x4700 #define END 0x4f00 #define SPACE 0x3920 #define ESC 0x011b #define ENTER 0x1c0d 这样只要事先用#define 这个宏定义,将要用的键盘码定义好,然后用switch语句分支各个键的功能即 可。这里多加说明一个函数kbhit(),其头文件为#include .当没有按键时,返回0值;有按键时,返 回非0值,结合while循环,就可实现键盘控制了。下面的函数功能是按上下左右键,屏幕上的正方形跟 着做出相应地移动,按逃跑键退出 /*control.c*/ #include /*delay()函数的头文件*/ #include #include #include #define LEFT 0x4b00 #define RIGHT 0x4d00 #define DOWN 0x5000 #define UP 0x4800 #define ESC 0x011b void main() { int gr = DETECT , gm = 0; int x = 100 , y = 100; int i , key; initgraph( &gr , &gm , "c:\\bgi" ) ; while ( 1 ) { while ( !kbhit() ) /*前面刚说完,不记得了,往上翻翻*/ { setfillstyle( SOLID_FILL , RED ); bar( x , y , x + 50 , y + 50 ); for (i = 0 ; i < 30 ; ++ i) delay( 10000 ); setfillstyle( SOLID_FILL , BLACK ); bar( x , y , x + 50 , y + 50 ); } key = bioskey( 0 ); /*前面刚说完,不记得了,往上翻翻*/ switch ( key ) { case LEFT: x -= 50; break; case RIGHT: x += 50; break; case UP: y -= 50; break; case DOWN: y += 50; break; case ESC: exit( 0 ); } } } 7、判断方块碰撞(即方块是否还能下落) 用一个带有返回值的函数,若碰撞则说明不能下落,返回1;反则说明没有碰撞,返回0. 具体一点就是整个4*4方块数组下落一个单位长度,与游戏空间数组(即前面说的“无盖的杯子”)有重叠的1,则在当前位置4*4数组是1的地方赋值给游戏空间对应的数组元素,表示停止下落,并画有1 的地方。对于左移、右移一个单位长度有重叠的1 ,则不允许左移、右移,继续自然下落。 8、消行 总的想法是先认为每一行都是满1的,从游戏空间的数组由上到下扫描,一旦测试到某一行中某个列元素为0,则认为这一行没满,跳出这行的扫描循环,进入下一行的扫描。 若扫描完某一行的元素都没有发现0,则以这行以上的每一行完完整整地将上一行的元素赋值给下一行,这个过程以由下到上进行,然后将整个游空间(GameSpace)画黒,再在GameSpace[21][12]中有1的地方画小正方形,如示例 A 0 0 0 1 0 0 从A行到D行扫描, A 0 0 0 0 0 0 B 1 1 0 1 0 1 扫描后发现C行是满的, B 0 0 0 1 0 0 C 1 1 1 1 1 1 则从B行起B行赋给C行,A行赋给B行, C 1 1 0 1 0 1 D 0 1 1 1 1 1 最后在最行A行赋全0 ,变成 D 0 1 1 1 1 1 对应的 ? 对应的 ? 图形 ? 图形 ? A?????? A?????? B?????? B?????? C?????? C?????? D?????? D?????? 读者可能会问这样不是每次都消一行而己,若要一次消两行以上怎么办(如恰好有一长条一次能消4行),这个简单,因为即使一次消多行也是建立在一行一行消的基础上的。把消行函数再细化成两部分,一部分为为扫描哪行满行并返回这个满行的行号的值,另一部分就消这个满行行号的行,用一个while 循环,判断条件为 “扫描函数(在我的程序里是fullrow())!= 0”,形如 while(fullrow() != 0 ) { 其中flrw是个整型变量,用来哪行满行,而clearrow(flrw) flrw=fullrow(); 则消指定的行。由于计算速度快,人眼看多次消行,就像一 clearrow( flrw ); 次搞掂的样子 } 9、极度重要的变形函数 分两部分讲 a、怎么变 b、变后插入到已有方块里的处理(即卡位处理),情况如图: ??????? ??????? ??????? ??????? ??????? ??????? ??????? 变形后 ??????? ??????? 有可能 ??????? ??????? ??????? ??????? ??????? a、怎么变。 其实我能想到两种方法,一种是把每个方块各种变形的样子都用结构体定义好(这样有19种),形成一个封闭的链表,变形一次指针指向下一种形状; 另一种是旋转90度,也是我选择的方法。 后一种是一种通法,但执行效率不比前一种方法快。下面针对旋转90度详细讲解。 网上说的旋转90度只是泛泛地说而已,经过毛概课上偷偷画方格,折纸,终于想到了一种主对角线对折,再翻来达到90度旋转的方法。请拿上一张纸,标上正面,反面,|、||,跟着图示做: 正面 反面 正面 ________ _______ _______ |\ | |\ | __|__ | /| | \ || | 沿对角线 ; | \ —| 再沿中轴 | | | | — / | | \ | 对折后 | \ | 翻过来 | | | 得 | / | | \ | | \ | |__|__| | / | | | \ | | 〓 \ | | | / 〓 | |_____\| |_____\| |/_____| 图(a) 图(b) 图(c) 对比图(a),图(c),则发现原来坚的东西变横了,也实现了顺时针转了90度。概念是这样,接下来是4*4数组怎么对折,只要仔细研究发现主对角线上的元素不必动,只要 0 1 2 3 0???? 0-1号与1-0号 1-2号与2-1号 2-3与3-2号 1???? 0-2号与2-0号 1-3号与3-1号 互相交换值, 2???? 0-3号与3-0号 3???? 再沿中轴互相交换值 0 1|2 3 0??|?? 0-0号与0-3号 0-1号与0-2号 1??|?? 1-0号与1-3号 1-1号与1-2号 2??|?? 2-0号与2-3号 2-1号与2-2号 3??|?? 3-0号与3-3号 3-1号与3-2号 | 这样就完成了第一部分。 b、变后插入到已有方块里的处理 (即卡位处理) 整体思路是先执行上面的第一部分,但不显示出来,然后判断是不是插到了已有方块中, 若可以左移或右移之后就可以的,我们就人为地移动它,后显示。 若左移或右移,又插入了右侧或左侧的方块,则逆序地执行第一部分,先执行中轴交换值,再对角线交换值,变回原来的形状,认为不具备变形的条件,后原形显示。 对于第一种情况,为分析情况,我们讨论每行的0、1、2、3号位置(注意这里的0、1、2、3号位置是4*4数组的每一行的,须要用循环一行行扫描),由于1、2号位置情况复杂且出现的机会少,故舍弃。因为(注意这里为了更好地说明,把长条????变成????,实际作图时还是????) 0 1 2 3 0 1 2 3 0 1 2 3 ???? ???? ???? ???? ? ???? ? ?????? ???? ? ???? ? ?????? ???? ? 变形后 ???? ? 这时1号卡 ?????? ? ? 有可能 ? ? 右移 两位 ? ? ? ? ? ? ? ? ?????? ?????? ?????? 又如 0 1 2 3 0 1 2 3 0 1 2 3 ???? ???? ???? ???? ? ???? ? ? ???? ???? ? ???? ? ? ???? ???? ? 变形后 ???? ? 这时1号卡 ? ???? 这时2号又卡了 ? ? 有可能 ? ? 右移两位 ? ? ? ? ? ? ? ? ????? ????? ????? 0 1 2 3 ???? ????? ????? 若右移一位 ????? 这时3号又卡了 ? ? ? ? ????? 由于1、2 号位的情况只会在长条(因为其它的方块长度最长为3)时出现,虽然存在移两位可行的情况,但实在是少,如要都完善的编写上,显得麻烦,故舍弃。 现在重点讨论0、3号位置。 0号位置由于变形后,有可能因为左侧位置不够而不能变形,只须稍微右移一个单位长度就可以了,如 0 1 2 3 0 1 2 3 0 1 2 3 ???? ???? ????? ???? ???? ????? ???? 变形后 ???? 移动后 ????? ???? ???? ????? ? ? ? ? ? ? 而人为地移动后,对应的1,2,3号位置又有可能插入了已有的方块中,如 0 1 2 3 0 1 2 3 0 1 2 3 ???? ???? ???? ???? ; ???? ????? ???? 变形后 ???? 右移一 ????? 1号又卡了 ???? ???? 位后 ????? ? ? ? ? ? ? ? ? ? ? ? ? 0 1 2 3 0 1 2 3 0 1 2 3 ???? ???? ???? ???? ???? ????? ???? 变形后 ???? 右移一 ????? 2号又卡了 ???? ???? 位后 ????? ? ? ? ? ? ? ? ? ? ? ? ? 0 1 2 3 0 1 2 3 0 1 2 3 ????? ???? ???? ????? ????? ????? ????? 变形后 ????? 右移一 ????? 3号又卡了 ????? ????? 位后 ????? ? ? ? ? ? ? ? ? ? ? ? ? 对于这些情况我们无奈,只能逆序变回原形。 3号位置的情况亦然,只不过是把左移变成右移,移动后讨论的是0,1,2号位置。 10、关于菜单的制作 我认为不会很难。概念上是把要显示的动态数值改变后,涂黒原来的地方,将新的数值在原来 的地方再 显示即可。特别值得一提的是,这之中可能用到的itoa()函数,头文件#include 。也许有人会问, 为什么要用itoa()函数,这是因为在图形模式下,用printf()输出只能是8*8点阵,白色字体。若想搞点比 较艺术的字体,输出的字体大点的,就看下面的函数是怎么实现的。 功能是按一下回车,数值增大100,按ESC退出。 /*itoa.c*/ #include #include #include #include #define ESC 0x011b #define ENTER 0x1c0D main() { int gr = DETECT , gm = 0; int key , value = 100 ; /*value是要转的整型变量*/ char str[10]; /*用来存的字符串*/ initgraph( &gr , &gm , "c:\\bgi" ) ; setbkcolor( BLACK ); /*设置背景颜色*/ /*对应的数值形式是setbkcolor( 0 )*/ setfillstyle( SOLID_FILL,BLACK );/*设置bar函数填充样式,这里为实心、黑色*/ /*对应的数值形式是setfillstyle( 1 , 0 )*/ settextjustify( LEFT_TEXT , CENTER_TEXT );/*设置文本输出的样式,*/ /*这里是左对齐,中心对齐*/ /*对应的数值形式是settextjustify( 0 , 1)*/ setcolor( CYAN ); /*设置输出文本的颜色,这里是青色*/ /*对应的数值形式是setcolor( 3 ) settextstyle ( SANS_SERIF_FONT , HORIZ_DIR , 3 );/*设置文本的字型,*/ /*这里是无衬线笔画字体,水平输出,3是24*24点阵*/ /*对应的数值形式是settextstyle ( 3 , 0 , 3 ) itoa( value , str , 10 ); /*前一个是要转成字符的整型变量名,*/ /*后一个是转成字符后用来存的字符串首址*/ /*itoa中的10是按10进制转化*/ while (1) { while ( !kbhit() ) { outtextxy(320,240,str); } key=bioskey( 0 ); switch ( key ) { case ENTER: bar(300,200,400,300); value += 100 ; itoa( value , str , 10 ); break; case ESC: exit( 0 ); } } } 好了,看到这相信你对这款游戏的制作已有所把握。 你可以先搞个没有键盘控制垂直下落的单一的测试方块,然后把向左、向右、向下加上,再把无盖的杯子画出来,让其有个范围,顺道搞掂碰撞,之后把消行功能加上,又将单一的测试方块变成7种随机的方块出现且最难搞的变形函数也完成了,补上记分功能,把菜单给做了,最后加上了自己的新功能。记住千里之行始于足下,聚沙成塔。我们有的是朩头、钉子、石头等各种零件,却不能忘记心中那宏伟的城堡!现在就一点点来吧。 ******************************************************************************* ******************************************************************************* 实现的源程序(菜单上好像还有小bugs,不影响大体) /*Russian_Diamond.c*/ #include #include /*主要应用于作图*/ #include /*主要应用于键盘*/ #include #include /*主要应用于产生随即数*/ #include /*主要应用于延时*/ /************************** 第一个界面的主要函数 ***************************/ void hello(); /*第一个界面的入口函数*/ void interface(); /*输出不许改变的文字信息 */ void activemenu(); /*选择菜单的动态显示函数*/ void menu_up(); /*选择菜单的向上函数*/ void menu_down(); /*选择菜单的向下函数*/ void menu_left(); /*选择菜单的减少速度值,难度值的函数*/ void menu_right(); /*选择菜单的增大速度值,难度值的函数*/ void menu_enter(); /*确定选项的函数*/ void menu_escape(); /*选择退出的函数*/ /************************ 第二个界面的主要函数 ************************/ void game(); /*选择开始游戏的入口函数*/ void gamestart(); /*第一次产生随机数*/ void initgamespace(); /*初始化游戏空间*/ void drawwal(); /*画边框与预览框*/ void drawsqa(); /*画下落方块*/ void showtext(); /*显示游戏过程中提示信息*/ void showvalue(); /*显示游戏过程中数值信息*/ void up(); /*游戏中变形函数*/ void down(); /*向下函数*/ void left(); /*向左函数*/ void right(); /*向右函数*/ void pause(); /*暂停函数*/ void escape(); /*显示退出菜单的函数*/ void speed_up(); /*加速函数*/ void speed_down(); /*减速函数*/ void wipe(); /*使用橡皮函数*/ void if_end(); /*判断游戏结束的函数*/ void preview(int ); /*预览框函数*/ void clearrow(int ); /*消行函数*/ void showscore(int ); /*显示分数的函数*/ void id(int ); /*为了能按照预览框的形状开始掉落而写的函数*/ int crash(); /*判断碰撞的函数*/ int fullrow(); /*侦测满行的函数*/ int next(); /*产生随机数的函数*/ /************************ 退出界面 ***********************/ void goodbye(); /*退出函数的入口*/ /************************ 第一个界面的主要参数值 ************************/ int start_color=14; /*说明当前选项到了确定选择的各个参数准备开始游戏的地方*/ int speed_color=3; /*说明当前选项到了选择速度的speed的地方*/ int difficulty_color=3; /*说明当前选项到了选择难度的difficulty的地方*/ int end_color=3; /*说明当前选项到了选择退出的end的地方*/ int menu_color=0; /*控制当前选项到了哪的重要判断标记*/ /************************ 游戏主体的各个全局变量 ************************/ #define LEFT 0x4b00 #define RIGHT 0x4d00 #define DOWN 0x5000 #define UP 0x4800 #define ESC 0x011b #define ENTER 0x1c0D #define SPACE 0x3920 #define W 0x1177 #define S 0x1f73 #define D 0x2064 #define UNIT 16 /*单位长度*/ #define spaLeft 188 /*游戏框的左上角*/ #define spaTop 34 /*由于作品上交时间急又由于出现了bug,已改动故现在已不是真正的左上角的数值 了,只能是概念上有个游戏框的左上角*/ #define staLeft 252 /*方块出现的初始地方*/ #define staTop 34 /*如上面说的那样,出现bug,而中间画图判断等用到原始的34,其实左上角y的数 值为staTop-UNIT*/ int a[ 11 ][ 4 ][ 4 ]={ /************************* 7 字形 *************************/ { {0,0,0,0}, {0,1,0,0}, {0,1,0,0}, {0,1,1,0} }, /*************************反 7 字形 *************************/ { {0,0,0,0}, {0,1,1,0}, {0,1,0,0}, {0,1,0,0} }, /************************* t 字形 *************************/ { {0,0,0,0}, {0,1,0,0}, {1,1,1,0}, {0,0,0,0} }, /************************* 小z 字形 *************************/ { {0,0,0,0}, {1,1,0,0}, {0,1,1,0}, {0,0,0,0} }, /************************* 小反 z 字形 *************************/ { {0,0,0,0}, {0,1,1,0}, {1,1,0,0}, {0,0,0,0} }, /************************* 长条 ************************/ { {0,1,0,0}, {0,1,0,0}, {0,1,0,0}, {0,1,0,0} }, /************************* 田 字形 *************************/ { {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0} }, /******************************* 选了难度为困难时才有的图形 ********************************/ /******************************** 杯子形 *********************************/ { {1,1,1,0}, {1,0,1,0}, {1,0,1,0}, {0,0,0,0} }, /************************* 大 Z 字形 *************************/ { {1,1,0,0}, {0,1,0,0}, {0,1,1,0}, {0,0,0,0} }, /************************* 大 Z 字形 *************************/ { {0,1,1,0}, {0,1,0,0}, {1,1,0,0}, {0,0,0,0} }, /************************* 一点 *************************/ { {0,0,0,0} {0,1,0,0}, {0,0,0,0}, {0,0,0,0} }, } ; int speed=0; /*速度变量*/ int difficulty=0; /*难度变量*/ int nandu; /*根据难度而确定产生的随机数的范围*/ int score=0; /*记录分数的变量*/ int eraser=0; /*记录橡皮的变量*/ int x , y; /*游戏界面的坐标*/ int GameSpace[ 26 ] [ 12 ] ;/*游戏空间的数组,以记录坐标*//*由于出现bug而不再是26行了,,又由 于上交时间紧是从第3号有效*/ int current[4][4]; /*为按照预览框的形状初始下落*/ int rec; /*为记录下个方块的形状*/ void main() { int gr = DETECT , gm = 0; initgraph( &gr , &gm , "c:\\bgi" ) ; hello(); /*是hello()中嵌有game(),goodbye()函数,通过选择进入不同的函数,goodbye()为出口*/ } /*game()中也嵌有hello(),goodbye()函数,通过选择进入不同的函数,goodbye()为出口*/ /****************************** 第一个界面的具体函数 *****************************/ void hello() { int key; /*记录按键的变量*/ char ch[1]; setbkcolor( BLACK ) ; interface(); /*输出不许改变的文字信息*/ settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); setcolor( WHITE ); switch ( difficulty ) { case 0: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(355,390,"easy"); break; case 1: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(340,390,"normal"); break; case 2: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(355,390,"hard"); break; } itoa(speed,ch,10); /*根据难度限制speed的范围并输出*/ outtextxy(370,360,ch); while (1) { while(!kbhit()) { activemenu(); /*若没按键一直根据相应的值输出*/ } key=bioskey(0); /*根据不同的按键,实现选择的功能*/ switch (key) { case UP: menu_up(); break; case DOWN: menu_down(); break; case LEFT: menu_left(); break; case RIGHT: menu_right(); break; case ENTER: menu_enter(); break; case ESC: menu_escape(); break; } } } /*********************** 游戏主体部分 ************************/ void game() { int i , j ; int key ; /*记录按键*/ int flrw; /*记录满行的所在行的行数*/ int times; /*记录在一次消行循环中消了多少行*/ setbkcolor( BLACK ) ; drawwal() ; /*画边界且画预览框的边界*/ initgamespace() ; /*初始化游戏空间*/ showtext(); /*显示提示信息*/ showvalue(); /*根据玩家所选的速度,难度输出信息*/ if (difficulty==2) /*根据难度而确定产生的随机数的范围*/ nandu=11; else nandu=7; gamestart(); /*主要是第一次产生随机数*/ while(1) { randomize(); while( ! kbhit() ) /*若有按键返回一个非零值*/ { if_end(); /*每次都判断游戏是否结束*/ if ( crash() == 1 ) /*若方块不再下落则坐标复位,又产生一个随机数*/ { x = staLeft; y = staTop-UNIT; id( rec ); rec =next(); preview( rec ); } if ( crash() == 0) /*若方块还可以下落,y坐标加一个单位长度*/ y += UNIT; for(times=0;fullrow()!=0;++times) /*消行部分,实质上是每次只消一行*/ { flrw=fullrow(); clearrow( flrw ); } if (times!=0) /*若有消行,记录分数*/ showscore ( times ); drawsqa( RED ); /*画红色方块*/ for ( i = 0; i < 25 - speed*4 ; ++i ) { if ( kbhit() ) /*为消除看起来很卡的感觉*/ { break; } delay( 5000 ) ; /*与画黑色色方块一起,达到动画效果*/ } drawsqa( BLACK ) ; /*与延时一起,达到动画效果*/ } key=bioskey(0); /*根据不同的按键,实现不同的功能*/ switch ( key ) { case DOWN: down(); break; case LEFT: left(); break; case RIGHT: right(); break; case UP: up(); break; case SPACE: pause(); break; case ESC: escape(); break; case W: wipe (); break; case S: speed_up(); break; case D: speed_down(); break; } } } /***************************** 退出界面的函数 *****************************/ void goodbye() /*为达到动态效果,写得稍微烦了点*/ { static int color=9; int i,j,tag=0; /*tag为标记变量*/ settextjustify( CENTER_TEXT,CENTER_TEXT ); settextstyle (0,0,7); while(1) { if (tag==1) /*标记变量若为1,跳出循环(即有按键则退出)*/ break; for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) /*若有按键,标记变量赋1,跳出循环,以下每个for 循环同样 */ { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 50,110,"T"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 110,110,"H"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 170,110,"A"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 230,110,"N"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 290,110,"K"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 430,110,"Y"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 490,110,"O"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 550,110,"U"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 240,190,"F"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 300,190,"O"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 360,190,"R"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 110,270,"P"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 170,270,"L"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 230,270,"A"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 290,270,"Y"); delay(10000); } for (j=0;j<1;++j,setcolor ( color ); if ( color==14 ) color=9; outtextxy( 110,270,"P"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 170,270,"L"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 230,270,"A"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 290,270,"Y"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 350,270,"I"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 410,270,"N"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 470,270,"G"); delay(10000); } for (j=0;j<1;++j,++color) { if (tag==1) break; if (kbhit()) { tag=1; break; } setcolor ( color ); if ( color==14 ) color=9; outtextxy( 530,270,"!"); delay(10000); } } getch(); exit(0); } /*************************************** 以下是开始菜单中各个函数的具体实现 **************************************/ void interface() { /********************* 画主要的线 *********************/ setlinestyle(0,0,THICK_WIDTH); setcolor(RED); line(80,0,80,479); line(0,285,639,285); setcolor(GREEN); line(87,0,87,479); line(0,292,639,292); setcolor(BLUE); line(94,0,94,479); line(0,299,639,299); /*************************** 显示相关的信息 ****************************/ setcolor ( BROWN ); settextjustify( CENTER_TEXT,CENTER_TEXT ); settextstyle (0,0,2); outtextxy( 325,60," Welcome to "); settextstyle (0,0,5); setcolor ( LIGHTCYAN ); outtextxy( 325,120,"RUSSIAN"); setcolor ( LIGHTMAGENTA ); outtextxy( 325,170,"DIAMOND"); setcolor ( LIGHTGRAY ); settextstyle (0,0,1); settextjustify( CENTER_TEXT,CENTER_TEXT ); outtextxy( 430,230,"by henry_black"); outtextxy( 430,250,"Jun 2nd 07"); /**************************** 显示菜单的文字 *************************/ setcolor ( CYAN ); settextjustify( RIGHT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy( 325,330,"GAME "); outtextxy( 317,360,"GAME SPEED"); outtextxy( 317,390,"DIFFICULTY"); outtextxy( 325,420,"GAME "); } void activemenu() { switch ( menu_color ) /*根据不同menu_color确定不同选项的颜色,达到选择的动态感*/ { case 0: start_color=14; speed_color=3; difficulty_color=3; end_color=3; break; case 1: start_color=3; speed_color=14; difficulty_color=3; end_color=3; break; case 2: start_color=3; speed_color=3; difficulty_color=14; end_color=3; break; case 3: start_color=3; speed_color=3; difficulty_color=3; end_color=14; break; } /*以下是根据确定不同选项的颜色值,输出各选项*/ settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); setcolor ( start_color ); outtextxy( 350,330,"START"); setcolor ( end_color ); outtextxy( 350,420," END "); setcolor ( speed_color ); /*画箭头*/ line(325,365,335,360); line(325,365,335,370); line(335,360,335,370); line(435,365,425,360); line(435,365,425,370); line(425,360,425,370); setcolor ( difficulty_color ); line(325,395,335,390); line(325,395,335,400); line(335,390,335,400); line(435,395,425,390); line(435,395,425,400); line(425,390,425,400); } void menu_up() { if (menu_color==0) /*若选到了最顶,再按就下到最下边的选项*/ menu_color=4; --menu_color; /*实现向上移动一个位置*/ } void menu_down() { if (menu_color==3) /*若选到了最底,再按就下到最上边的选项*/ menu_color=-1; ++menu_color; /*实现向下移动一个位置*/ } void menu_left() /*该函数为减小speed,difficulty的值*/ { char ch[1]; /*为把数值转字符输出*/ if (menu_color == 1 ) /*说明当前选项为速度*/ { if (speed==0 && difficulty!=0) /*根据难度,确定范围并从最小值变成最大值*/ speed=6; if (speed==0 && difficulty==0) speed=4; --speed; setfillstyle(0,BLACK); /*先画黑,再转字符输出*/ bar(345,355,385,375); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); itoa(speed,ch,10); outtextxy(370,360,ch); } if (menu_color == 2) /*说明当前选项为难度*/ { if (difficulty==0) /*最小值变成最大值*/ difficulty=3; --difficulty; switch ( difficulty ) /*根据difficulty的值,先画黑,再输出相应的信息*/ { case 0: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(355,390,"easy"); break; case 1: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(340,390,"normal"); break; case 2: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(355,390,"hard"); break; } } } void menu_right() /*该函数为增大speed,difficulty的值*/ { char ch[1]; if (menu_color == 1 ) /*说明当前选项为速度*/ { if (speed==5 && difficulty!=0) /*根据难度,确定范围并从最大值变成最小值*/ speed=-1; if (speed==3 && difficulty==0) speed=-1; ++speed; setfillstyle(0,BLACK); /*先画黑,再转字符输出*/ bar(345,355,385,375); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); itoa(speed,ch,10); outtextxy(370,360,ch); } if (menu_color == 2) /*说明当前选项为难度*/ { if (difficulty==2) /*最大值变成最小值*/ difficulty=-1; ++difficulty; switch ( difficulty ) /*根据difficulty的值,先画黑,再输出相应的信息*/ { case 0: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(355,390,"easy"); break; case 1: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(340,390,"normal"); break; case 2: setfillstyle(0,BLACK); bar(338,385,420,410); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); outtextxy(355,390,"hard"); break; } } } void menu_enter() { if (menu_color == 0) /*说明当前选项为开始游戏*/ { cleardevice(); /*若按回车则开始*/ game(); } if (menu_color == 3) /*说明当前选项为退出游戏*/ { cleardevice(); /*若按回车则退出*/ goodbye(); } } void menu_escape() /*若在选择时按esc键,直接跳到退出选项*/ { menu_color=3; } /******************************************* 以下是game()函数中各个相关的函数的具体实现 *********************************************/ void gamestart() /*主要是开始时第一次产生随机数*/ { randomize(); score=0; eraser=0; x = staLeft; y = staTop-UNIT; rec=rand()%nandu; id( rec ); rec=rand()%nandu; preview( rec ); } void initgamespace() { int i , j ; for ( i = 0 ; i < 25 ; ++ i ) for ( j = 1 ; j < 11 ; ++ j ) GameSpace[ i ][ j ] = 0 ; /*中间赋0,说明没有被占有*/ for ( i = 1 ; i < 11 ; ++ i ) GameSpace[ 25 ][ i ] = 1 ; /*最下边赋1,为了不让方块超出底部*/ for ( i = 0 ; i < 2 ; ++ i ) for( j = 0 ; j < 26 ; ++ j ) GameSpace[ j ][ i*11 ] = 1 ; /*两侧赋1,为了不让方块超出边界*/ } void drawwal() { int i , j ; /************** 画预览框 *************/ setfillstyle( SOLID_FILL , YELLOW ) ; /*先画大黄框*/ bar( 465 , 115 , 555 , 205 ) ; setfillstyle( SOLID_FILL , BLACK ) ; /*再中间画小黑框*/ bar( 473 , 123 , 547 , 197 ) ; /*************** 画游戏空间的边界 ****************/ setfillstyle( SOLID_FILL , YELLOW ) ; x = 204 ; y = 34 ; setcolor( 0 ) ; setlinestyle(0,0,1); for ( j = 0 ; j < 10 ; ++ j ) { bar3d( x+j*UNIT , y +48 , x+j*UNIT+UNIT , y+64 , 0 , 1 ) ; bar3d( x+j*UNIT , y+400 , x+j*UNIT+UNIT , y+416 , 0 , 1 ) ; } x = 188 ; y = 34 ; for ( i = 0 ; i < 2 ; ++ i ) for ( j = 3 ; j < 26 ; ++ j ) bar3d ( x+i*176 , y+j*UNIT , x+i*176+UNIT , y+j*UNIT+UNIT , 0 , 1 ) ; } void drawsqa( int color ) /*根据传进来的颜色画红的方块,黑的方块*/ { int i , j; setfillstyle( SOLID_FILL , color ); for ( i = 0 ; i < 4 ; ++ i ) for( j=0 ; j<4 ; ++ j ) { /*画的时候只画方块数组中有1的地方*/ if ( (y + i * UNIT > staTop+48) && current[j] == 1) /*方块其实是从最顶还要上的地方开始掉落,为 */ 好看 bar3d( x + j * UNIT , y + i * UNIT , x + j * UNIT + UNIT , y + i * UNIT + UNIT , 0 , 0 ) ; } } void showtext() /*为显示游戏中的提示信息*/ { int point1 [10]={15,40,180,40,180,240,15,240,15,40}; int point2 [18]={60,260,140,260,180,305,180,388,140,432,60,432,20,388,20,305,60,260}; setlinestyle(0,0,3) ; /******************* 左上角 ******************/ setcolor( LIGHTBLUE ); drawpoly(5,point1); setcolor( BROWN ); settextjustify(RIGHT_TEXT,TOP_TEXT); settextstyle(0,0,0); outtextxy(130,70,"TURN AROUND : "); outtextxy(130,85,"FALL DOWN : "); outtextxy(130,100,"LEFTWARD : "); outtextxy(130,115,"RIGHTWARD : "); outtextxy(130,130,"SPEED UP : "); outtextxy(130,145,"SPEED DOWN : "); outtextxy(130,160,"WIPE OFF : "); outtextxy(130,175,"PAUSE : "); outtextxy(130,190,"CONFIRM : "); outtextxy(130,205,"EXIT : "); setcolor( LIGHTGRAY ); settextjustify(LEFT_TEXT,TOP_TEXT); outtextxy(130,70,"UP"); outtextxy(130,85,"DOWN"); outtextxy(130,100,"LEFT"); outtextxy(130,115,"RIGHT"); outtextxy(130,130,"S"); outtextxy(130,145,"D"); outtextxy(130,160,"W"); outtextxy(130,175,"SPACE"); outtextxy(130,190,"ENTER"); outtextxy(130,205,"ESCAPE"); /************** 左下角 **************/ setcolor( LIGHTCYAN ); drawpoly(9,point2); settextstyle(3,HORIZ_DIR,1); settextjustify(RIGHT_TEXT,TOP_TEXT); setcolor( LIGHTMAGENTA ); outtextxy(100,300,"score :"); outtextxy(100,320,"speed :"); outtextxy(100,340,"eraser :"); outtextxy(120,360,"difficulty :"); /*********************** 游戏框中上 ************************/ settextstyle(0,HORIZ_DIR,2); settextjustify(LEFT_TEXT,TOP_TEXT); setcolor( GREEN ); outtextxy(225,55,"ENJOY IT"); /************ 右下角 **************/ setcolor( MAGENTA ); settextstyle(0,HORIZ_DIR,0); settextjustify(CENTER_TEXT,CENTER_TEXT); outtextxy(510,230,"GuiLin University of "); outtextxy(510,245,"Electronica Technology"); setcolor( YELLOW ); outtextxy(510,270,"Department of Computer"); setcolor( BLUE); outtextxy(510,295,"Major of SoftWare"); setcolor( LIGHTRED ); outtextxy(570,375,"by henry_black"); outtextxy(570,390,"Jun 2nd,07"); setcolor( GREEN ); settextjustify(LEFT_TEXT,CENTER_TEXT); outtextxy(410,320,"QQ : 42595947"); outtextxy(410,335,"nick name : Count. Black"); setcolor(BLACK); setlinestyle(0,0,1); } void showvalue() { char ch[7]; /*为把数值转字符输出*/ /*************** 输出分数 *****************/ setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,2); itoa(score,ch,10); outtextxy(105,310,ch); /*************** 输出速度 ****************/ itoa(speed,ch,10); outtextxy(105,330,ch); /*************** 输出橡皮数 ****************/ itoa(eraser,ch,10); outtextxy(105,350,ch); /*************** 输出难度 ****************/ settextjustify( CENTER_TEXT,CENTER_TEXT ); if (difficulty==0) outtextxy(110,390,"easy"); if (difficulty==1) outtextxy(110,390,"normal"); if (difficulty==2) outtextxy(110,390,"hard"); setcolor(BLACK); } /***************************** 极度核心的变形函数 *****************************/ void up() { /*整体思路是先变形,后判断,若不可变形则变回;若可变形则不变,再画图形*/ int i,j,k,l,temp,tag,lab; /*需要两个标记变量*/ for ( i = 0 ; i < 3 ; ++ i ) /*主对角线对折*/ for ( j = i+1 ; j < 4 ; ++ j ) { temp = current[ i ][ j ]; current[ i ][ j ] = current[ j ][ i ]; current[ j ][ i ] = temp ; } for( i= 0 ; i < 4 ; ++ i) /*竖中轴对折*/ for( j = 0 ; j < 2 ; ++ j) { temp = current[ i ][ j ] ; current[ i ][ j ] = current[ i ][ 3-j ] ; current[ i ] [3-j ] = temp ; } tag=0; /*标记变量为跳出循环,当为1时跳出循环*/ for( i= 0 ; i < 4 ; ++ i) { /*变形后有可能插入已为1的地方,分情况讨论,讨论每行的第0,1,2,3号位置*/ /****************************** 由于第1,2号位置情况复杂,且出现的情况极少,故舍弃。一有这种情况发生则认为不能变形跳出循环 ************************************************************************************************/ if ( (GameSpace [ (y - spaTop) / UNIT + i ] [ (x - spaLeft) / UNIT + 1 ] == current[ i ][1]) && current[ i ] [1] == 1 ) { tag=1; break; } if ( (GameSpace [ (y - spaTop) / UNIT + i ] [ (x - spaLeft) / UNIT + 2 ] == current[ i ][2]) && current[ i ] [2] == 1 ) { tag=1; break; } /*************************************************************************************************** 第0号位置由于变形后,有可能只是因为左侧位置不够而不能变形,只须稍微向右移动一个单位长度就 可以了的 ****************************************************************************************************/ if ( (GameSpace [ (y - spaTop) / UNIT + i ] [ (x - spaLeft) / UNIT] == current[ i ][0]) && current[ i ] [0] == 1 ) { x+=UNIT; lab=0; /********************************************************************************************************************* ******** 人为的移动后,可能对应的第1,23号位置有可能也已经有物体,若有则说明即使移动了一个单位长度也 还是不够的两个标记位均赋1,跳出循环 ********************************************************************************************************************** ********/ for (k=0;k<4;++k) for (l=1;l<4;++l) { if (lab==1) break; if((GameSpace [ (y - spaTop) / UNIT +k] [ (x - spaLeft) / UNIT+l] == current[k][l]) && current[k] [l] == 1) { tag=1; x-=UNIT; lab=1; } } } /****************************************************************************************************** 第3号位置由于变形后,有可能只是因为右侧位置不够而不能变形,只须稍微向左移动一个单位长度就 可以了的 *********************************************************************************************************/ if ( (GameSpace [ (y - spaTop) / UNIT + i ] [ (x - spaLeft) / UNIT+3] == current[ i ][3]) && current[ i ] [3] == 1 ) { x-=UNIT; lab=0; /********************************************************************************************************************* ******** 人为的移动后,可能对应的第0,1,2号位置有可能也已经有物体,若有则说明即使移动了一个单位长度 也还是不够的两个标记位均赋1,跳出循环 ********************************************************************************************************************** ********/ for (k=0;k<4;++k) for (l=0;l<3;++l) { if (lab==1) break; if((GameSpace [ (y - spaTop) / UNIT +k] [ (x - spaLeft) / UNIT+l] == current[k][l]) && current[k] [l] == 1) { tag=1; x+=UNIT; lab=1; } } } } switch ( tag ) /*若标记变量始终为0,则说明没有插到别的有一的地方*/ { case 0: break; case 1: /*若标记变量始终为1,则说明插到别的有一的地方,须变回来*/ for( i= 0 ; i < 4 ; ++ i) /*逆序,先竖中轴对折*/ for( j = 0 ; j < 2 ; ++ j) { temp = current[ i ][ j ]; current[ i ][ j ] = current[ i ][ 3-j ] ; current[ i ] [3-j ] = temp ; } for ( i = 0 ; i < 3 ; ++ i ) /*再主对角线对折*/ for ( j = i+1 ; j < 4 ; ++ j ) { temp = current[ i ][ j ]; current[ i ][ j ] = current[ j ][ i ]; current[ j ][ i ] = temp ; } break; } } void down() { if (crash()==0) /*向下若不碰撞,则y坐标加一个单位长度*/ y += UNIT ; } void left() { int i , j , tag=0; /*标记变量跳出循环体,这是一种方法*/ for( i = 0 ; i < 4 ; ++ i ) for( j = 0 ; j < 4 ; ++ j ) { /************************************************************************************************************** 若整个方块数组向左一个单位长度,与游戏空间有重叠的1,说明下落的方块左边以有物体,不能向左,一检测重叠有就跳出循环 ***************************************************************************************************************/ if ( ( GameSpace[ ( y - spaTop ) / UNIT + i ] [( x - spaLeft - UNIT ) / UNIT + j] == current[ i ][ j ] ) && current[ i ][ j ] == 1 ) { if ( tag == 1) break; tag = 1 ; } } if ( tag == 0 ) /*标记变量始终不改变则说明可以向左移动*/ x -= UNIT ; } void right() { int i , j , tag = 0 ; for( i = 0 ; i < 4 ; ++ i ) for( j = 0 ; j < 4 ; ++ j ) { /******************************************************* ******************************************************* 若整个方块数组向右一个单位长度,与游戏空间有重叠的1,说明下落的方块右边已有物体,不能向右,一检测重叠有就跳出循环 ***************************************************************************************************************/ if ( ( GameSpace[ ( y - spaTop ) / UNIT + i ] [( x - spaLeft + UNIT ) / UNIT + j] == current[ i ][ j ] ) && current[ i ][ j ] == 1 ) { if ( tag == 1) break; tag = 1 ; } } if ( tag == 0) /*标记变量始终不改变则说明可以向右移动*/ x += UNIT ; } void pause() { settextstyle(0,HORIZ_DIR,0); settextjustify(LEFT_TEXT,TOP_TEXT); setcolor( WHITE ); outtextxy(225,35,"press any key"); getch(); /*主要应用getch()的性质*/ setfillstyle( SOLID_FILL , BLACK ); bar(225,35,350,50); setcolor( BLACK ); } void escape() { int key; /*按键值的记录*/ int esc_color=0; /*控制当前选项到了哪的重要判断标记*/ int try_color=9; /*说明当前选项到了选择重玩的地方*/ int order_color=8; /*说明当前选项到了返回hello()界面的地方*/ int exit_color=8; /*说明当前选项到了选择退出的地方*/ while(1) { while(!kbhit()) /*若不按键,整个游戏停留在选项上*/ { switch ( esc_color ) /*根据标记显示不同的颜色,以说明到了哪个选项*/ { case 0: try_color=9; order_color=8; exit_color=8; break; case 1: try_color=8; order_color=9; exit_color=8; break; case 2: try_color=8; order_color=8; exit_color=9; break; } settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,3); setcolor(try_color); outtextxy(445,35,"TRY AGAIN "); setcolor(order_color); outtextxy(464,60," MENU "); setcolor(exit_color); outtextxy(470,85," EXIT "); } key=bioskey(0); switch ( key ) { case UP: if (esc_color == 0) /*若选到了最顶,再按就下到最下边的选项*/ esc_color=3; --esc_color; break; case DOWN: if (esc_color == 2) /*若选到了最底,再按就下到最上边的选项*/ esc_color=-1; ++esc_color; break; case ENTER: if (esc_color == 0) /*若选到了重玩,按回车则重新游戏*/ { cleardevice(); game(); } if (esc_color == 1) /*若选到了最开始的界面,按回车则到开始界面*/ { cleardevice(); hello(); } if (esc_color == 2) /*若选到了退出,按回车则退出游戏*/ { cleardevice(); goodbye(); } break; case ESC: /*若按esc键,则直接跳到推出选项*/ esc_color = 2; break; } } } void speed_up() { char ch[2]; if ( (speed==3) && (difficulty==0) ) /*根据所选难度,加速到在一定范围的速度后不再加速*/ ; else if (speed==5) ; else ++speed; setfillstyle( SOLID_FILL , BLACK ) ; /*根据改变的值,输出对应的信息*/ bar(105,325,170,343); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,2); itoa(speed,ch,10); outtextxy(105,330,ch); setcolor(BLACK); } void speed_down() /*根据所选难度,减慢到在一定范围的速度后不再减慢*/ { char ch[2]; if ( (speed==0)) ; else --speed; setfillstyle( SOLID_FILL , BLACK ) ; /*根据改变的值,输出对应的信息*/ bar(105,325,170,343); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,2); itoa(speed,ch,10); outtextxy(105,330,ch); setcolor(BLACK); } void wipe() { char ch[2]; int i; if ( eraser!=0 ) /*当橡皮还有时,消两次最底下那行,并橡皮减1*/ { for(i=0;i<2;++i) clearrow(24); --eraser; } setfillstyle( SOLID_FILL , BLACK ) ; /*根据还剩的橡皮数,输出相应的信息*/ bar(105,345,170,363); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,2); itoa(eraser,ch,10); outtextxy(105,350,ch); setcolor(BLACK); } void if_end() { int i,tag=0; for (i=1;i<11;++i) if ( GameSpace[3]==1) /*最顶上一检测出有方块,则结束*/ { tag=1; break; } if (tag==1) /*标记变量为一说明,游戏结束,进入退出的菜单*/ { escape(); } } void preview(int for_next) { int i,j; setfillstyle( SOLID_FILL , BLACK ) ; /*先画黑*/ bar( 473 , 123 ,547 , 197 ) ; setfillstyle(SOLID_FILL,RED); /*再画方块数组中有1的地方*/ for (i=0;i<4;++i) for (j=0;j<4;++j) if (a[ for_next ][j]==1) bar3d(480+j*UNIT,128+i*UNIT,480+j*UNIT+UNIT,128+i*UNIT+UNIT,0,0); setfillstyle(SOLID_FILL,BLACK); } void clearrow( int temp) { int i , j ; /************************************************************************* 根据传进来满行的所在行的编号,从那行起由下到上每行的上一行的值赋给这行 ***************************************************************************/ for (i=temp;i>0;--i) for(j=1;j<11;++j) GameSpace[ i ][ j ] = GameSpace[ i -1 ][ j ] ; setfillstyle(SOLID_FILL,BLACK); /*整个游戏空间画黑*/ bar(spaLeft+UNIT,spaTop+64,spaLeft+UNIT+160,spaTop+UNIT+384); setfillstyle (SOLID_FILL,RED); /*画红方块,再游戏空间中有1 的地方*/ for (i=1;i<25;++i) for (j=1;j<11;++j) if (GameSpace[j]==1) { bar3d(spaLeft+j*UNIT,spaTop+i*UNIT,spaLeft+j*UNIT+UNIT,spaTop+i*UNIT+UNIT,0,0); } setfillstyle(SOLID_FILL,BLACK); setcolor(BLACK); } void showscore(int t) { char ch[6]; switch( t ) /*根据传进来的一次消行循环中消了多少行,确定加多少分*/ { case 0: break; case 1: score+=10; break; case 2: score+=20; break; case 3: score+=40; break; case 4: score+=60; break; } setfillstyle( SOLID_FILL , BLACK ) ; bar(105,305,170,323); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,2); itoa(score,ch,10); outtextxy(105,310,ch); if ( (score%1000==0) && (score!=0)) /*若分数每满1000分,速度加1*/ { if ( (speed==3) && (difficulty==0) ) /*若选的难度为简单,速度最大为3*/ ; else if (speed==6) /*别的最大为6*/ ; else ++speed; setfillstyle( SOLID_FILL , BLACK ) ; /*根据速度的值,先画黑再输出*/ bar(105,325,170,343); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,2); itoa(speed,ch,10); outtextxy(105,330,ch); } if ( (score%500==0) && score!=0) /*若分数每满500分,橡皮加1*/ { ++eraser; setfillstyle( SOLID_FILL , BLACK ) ; /*根据橡皮数,先画黑再输出*/ bar(105,345,170,363); setcolor( WHITE ); settextjustify( LEFT_TEXT,CENTER_TEXT ); settextstyle (1,0,2); itoa(eraser,ch,10); outtextxy(105,350,ch); } setcolor(BLACK); } void id(int rec) /*为了能按照预览框的形状开始掉落*/ { int i , j ; for ( i = 0 ; i < 4 ; ++ i ) for ( j = 0 ; j < 4 ; ++ j ) current[ i ][ j ]=a[ rec ][ i ][ j ]; } /************************ 极度核心的碰撞函数 ************************/ int crash() { int i , j , k ,l; /**************************************************************************************************************** 若方块数组整体下移一个单位长度,与游戏空间有重叠的1,则在当前位置赋值给游戏空间,表示停止下 1的地方 落,并画红有 *****************************************************************************************************************/ for ( i = 0 ; i < 4; ++ i ) for ( j = 0 ; j <4 ; ++j ) if ( ( GameSpace[ ( y - spaTop + UNIT ) / UNIT + i ][ ( x - spaLeft ) / UNIT + j ] == current [ i ][ j ] ) && (current[ i ][ j ] == 1) ) { for ( k = 0 ; k < 4 ; ++ k ) for ( l = 0 ; l < 4 ; ++ l ) if (current[k][l]==1) /*只能赋下落数组中是1的地方,为解决这个错误用了三天*/ GameSpace[ ( y - staTop ) / UNIT + k ][ ( x - spaLeft ) / UNIT + l ] = current[ k ][ l ]; setfillstyle( SOLID_FILL , RED ); for ( k = 3 ; k < 25 ; ++ k ) for ( l = 1 ; l < 11 ; ++ l ) { if( GameSpace[k][l] == 1 ) bar3d( spaLeft + l * UNIT, spaTop + k * UNIT, spaLeft + l * UNIT + UNIT,spaTop + k * UNI T + UNIT, 0, 0); } setfillstyle( SOLID_FILL , BLACK ); return 1; /*若有赋值返回1说明碰撞了*/ } return 0; /*若经过了判断,则返回0说明没有碰撞*/ } int fullrow() { /*若有满行,也每次只返回一行的行编号*/ int i, j, tag; for (i=1;i<25;++i) { tag=1; /*先认为满行,标记变量赋初值为1*/ for (j=1;j<11;++j) { if (GameSpace[j]==0) /*若发现一行中一有0,说明这行没满,跳出扫下一行*/ { tag=0; break; } } if (tag == 1) /*若当前i行满行,返回该行值,即*/ return (i); } if (i==25) /*扫描了整个游戏空间,i为25说明没有满行*/ return (0); } int next() { /*主要产生一个随机数*/ int i; randomize(); i=rand()%nandu; return i; }
/
本文档为【俄罗斯方块c语言详解】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索