俄罗斯方块c语言详解.docx

上传人:b****8 文档编号:9423264 上传时间:2023-02-04 格式:DOCX 页数:62 大小:38.08KB
下载 相关 举报
俄罗斯方块c语言详解.docx_第1页
第1页 / 共62页
俄罗斯方块c语言详解.docx_第2页
第2页 / 共62页
俄罗斯方块c语言详解.docx_第3页
第3页 / 共62页
俄罗斯方块c语言详解.docx_第4页
第4页 / 共62页
俄罗斯方块c语言详解.docx_第5页
第5页 / 共62页
点击查看更多>>
下载资源
资源描述

俄罗斯方块c语言详解.docx

《俄罗斯方块c语言详解.docx》由会员分享,可在线阅读,更多相关《俄罗斯方块c语言详解.docx(62页珍藏版)》请在冰豆网上搜索。

俄罗斯方块c语言详解.docx

俄罗斯方块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,GameSpace[20][y](其中y从0到11)初始都为1。

 012345678910

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字形”

可看作:

0123

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"。

  voidfarinitgraph(intfar*graphdriver,intfar*graphmode,charfar*pathtodriver);graphdriver是上涨指向图形驱动序号变量的指针;graphmode是在graphdriver选定后,指向图形显示模式序号变量的指针。

pathtodriver表示存放图形驱动文件的路径。

特别值得一提的是驱动文件路径的写法,由于有转义字符,如bgi文件夹(一般这个文件夹就在Tc文件夹目录下,这个说明文档黙认bgi在c:

\,后面举的例子亦然)在c:

\,写的时候很多人写成"c:

\bgi",少了个\,应写成"c:

\\bgi",切记。

 此外,我还强烈建议借一本叫《c作图与c汉字技术》的书,这是我见过介绍c绘图方面最全面的书了,为了节省时间,可以直接看这几个函数,这些函数均包含在头文件#include

voidline(intx,inty,intxx,intyy);/*从(x,y)到(xx,yy)处以setcolor()决定的颜色画直线*/

voidsetlinestyle(intlinestyle,unsignedupattern,intthickness);  

            /*linestyle变化范围为0~4,也可以是大写的英文*/

            /*分别表示实线,点线,中心线,点画线,用户自定义线*/

            /*upattern处一般写0*/

          /*thickness只有1、3两个值,分别表示一个像素宽,三个像素宽*/

             

voidsetcolor(intcolor); /*决定前景颜色,color变化范围为0~15也可以是大写的英文*/

voidsetbkcolor(intcolor); /*决定背景颜色,color变化范围为0~15也可以是大写的英文*/

voidrectangle(intx,inty,intxx,intyy);/*以(x,y)为左上角,以(xx,yy)为右下角画矩形*/

voidbar(intx,inty,intxx,intyy); /*以(x,y)为左上角,以(xx,yy)为右下角画条形*/

voidbar3d(intx,inty,intxx,intyy,intdepth,inttopflag);

             /*以(x,y)为左上角,以(xx,yy)为右下角画立体条形*/

             /*depth决定了三维直方图的长度*/

             /*当topflag非0时,画出三维顶,否则不画出三维顶*/

voidsetfillstyle(intpattern,intcolor);/*pattern变化范围为0~12也可以是大写的英文*/

             /*color变化范围为0~15也可以是大写的英文*/

char*itoa(intn,char*str,intradix);/*n是要转的整型变量*/

 /*str用来存的字符串*/

 /*radix是按什么进制转化*/

      

/*能将整型数字转成字符型数字,结合outtextxy()*/

             /*可将得分、菜单上的数值等简单地显示在屏幕上*/

voidsettextjustify(inthoriz,intvert);

/*horiz变化范围为0~2,也可以是大写的英文,分别代表左对齐,字符串中心对齐,右对齐*/

/*vert变化范围为0~2,也可以是大写的英文,分别代表底部对齐,中心对齐,顶部对齐*/

voidsettextstyle(intfont,intdirection,intcharsize);

/*font变化范围为0~12也可以是大写的英文*/

/*direction只能是0、1,也可以是大写的英文,0、1分别代表水平输出,垂直输出*/

/*charsize变化范围为1~10也可以是大写的英文,数值越大,字体越大*/

voidouttextxy(intx,inty,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,如长条可表示为

0123

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()函数的头文件*/

voidmain()

{

 intgr=DETECT,gm=0;

 intx=50,y=50;

 inti,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();

intbioskey(intcmd);

  当cmd为1时,bioskey()检测是否有键按下。

没有键按下时返回0;有键按下时返回键盘码(任何键盘码都不为0),但此时并不将检测到的按键码从键盘缓冲队列中清除。

  当cmd为0时,bioskey()返回键盘缓冲队列中的键盘码,并将此按键码从键盘缓冲队列中清除。

如果键盘缓冲队列为空,则一直等到有键按下,才将得到的键盘码返回。

  Escape键的按键码为0x11b,下面的小程序可以获取按键的键盘码

/*keyboard_code.c*/

#include

#include

voidmain()

{

 intkey;

 while

(1)

 {

   key=bi

oskey(0);  /*waitforakeystrike*/

   printf("0x%x\n",key);

   if(key==0x11b)

    break;     /*Escape*/

 }

}

常用按键的按键码如下:

#defineLEFT0x4b00

#defineRIGHT0x4d00

#defineDOWN0x5000

#defineUP 0x4800

#defineHOME0x4700

#defineEND 0x4f00

#defineSPACE0x3920

#defineESC 0x011b

#defineENTER0x1c0d

 这样只要事先用#define这个宏定义,将要用的键盘码定义好,然后用switch语句分支各个键的功能即可。

这里多加说明一个函数kbhit(),其头文件为#include.当没有按键时,返回0值;有按键时,返回非0值,结合while循环,就可实现键盘控制了。

下面的函数功能是按上下左右键,屏幕上的正方形跟着做出相应地移动,按逃跑键退出

/*control.c*/

#include  /*delay()函数的头文件*/

#include

#include

#include

#defineLEFT0x4b00

#defineRIGHT0x4d00

#defineDOWN0x5000

#defineUP 0x4800

#defineESC 0x011b

voidmain()

{

 intgr=DETECT,gm=0;

 intx=100,y=100;

 inti,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)

{

 caseLEFT:

 x-=50;

 break;

 caseRIGHT:

 x+=50;

 break;

 caseUP:

 y-=50;

 break;

 caseDOWN:

 y+=50;

 break;

 caseESC:

 exit(0);

}

}

}

7、判断方块碰撞(即方块是否还能下落)

 用一个带有返回值的函数,若碰撞则说明不能下落,返回1;反则说明没有碰撞,返回0.

 具体一点就是整个4*4方块数组下落一个单位长度,与游戏空间数组(即前面说的“无盖的杯子”)有重叠的1,则在当前位置4*4数组是1的地方赋值给游戏空间对应的数组元素,表示停止下落,并画有1的地方。

对于左移、右移一个单位长度有重叠的1,则不允许左移、右移,继续自然下落。

8、消行

 总的想法是先认为每一行都是满1的,从游戏空间的数组由上到下扫描,一旦测试到某一行中某个列元素为0,则认为这一行没满,跳出这行的扫描循环,进入下一行的扫描。

 若扫描完某一行的元素都没有发现0,则以这行以上的每一行完完整整地将上一行的元素赋值给下一行,这个过程以由下到上进行,然后将整个游空间(GameSpace)画黒,再在GameSpace[21][12]中有1的地方画小正方形,如示例

A000100 从A行到D行扫描,      A000000

B110101 扫描后发现C行是满的,    B000100

C111111 则从B行起B行赋给C行,A行赋给B行,C110101

D011111 最后在最行A行赋全0,变成   D011111

对应的 ↓             对应的 ↓

图形 ↓             图形 ↓

A□□□■□□            A□□□□□□

B■■□■□■            B□□□■□□

C■■■■■■            C■■□■□■

D□■■■■■            D□■■■■■

读者可能会问这样不是每次都消一行而己,若要一次消两行以上怎么办(如恰好有一长条一次能消4行)?

这个简单,因为即使一次消多行也是建立在一行一行消的基础上的。

把消行函数再细化成两部分,一部分为为扫描哪行满行并返回这个满行的行号的值,另一部分就消这个满行行号的行,用一个while循环,判断条件为“扫描函数(在我的程序里是fullrow())!

=0”,形如

while(fullrow()!

=0)

{        其中flrw是个整型变量,用来记录哪行满行,而clearrow(flrw)

 flrw=fullrow();    则消指定

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 教学研究 > 教学反思汇报

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1