当前位置:文档之家› 俄罗斯方块实验报告

俄罗斯方块实验报告

俄罗斯方块实验报告编写“俄罗斯方块”游戏1、问题分析。

编写俄罗斯方块游戏,首先是界面问题,要有一个相对美观的游戏界面,可以有很多种解决的方法,可以用DOS的界面,也可以用MFC做。

界面做好后,最重要的就是七个方块如何存放,翻转,显示等等一系列问题,首先,我们要把这七个方块用一种数据结构存储起来;其次,在游戏中将这七个方块随机挑选出来并显示在屏幕上,根据键盘事件进行旋转;最后,判断到达底部的方块是简单叠加还是引发消除事件。

普通俄罗斯方块游戏中,只有七个基本方块:|,Z,N,L,7,|-,O,方块都可以画在一个4*4的方格中。

于是就有两个方法:一个是只存储七个方块,在游戏运行的时候计算旋转后的方块形状;另一个是将所有的方块全部存储起来,在游戏运行的时候计算取其中的哪个方块。

另外,考虑到4*4是16,而一个int正好是16位(TC2是16位,其他的是32位),所以可以把一个方块存储在一个int数据中,取出的时候,判断它的每个bit位,为1处有小方块,为0处是空白。

所以可以分别用二维数组和bit的方法来表示这些方块。

对于二维数组而言,其控制旋转的操作会很简单,就是控制数组的行列以决定到底该取出哪一种方块,所以程序中我会采用这种方法。

如何控制方块的下落速度,如何让实现左移,右移,下落,如何销行,如何计分,又如何加速等等都是需要考虑的问题。

对于控制方块的下落速度,首先应该现弄明白方块是怎样下落的,目前最常用的就是每隔一定得时间进行重新绘图,就像动画片一样,当很多副相关的画面不断在人眼前播放,由于人眼的掩蔽效应就会形成动着的画面,看起来就是物体在那里移动,于此原理相同,当改变方块在画面上的位置,再以一定得时间间隔进行重新刷图,其效果看起来就是方块在移动;也就是说控制方块下落速度的其实就是控制重新绘图的时间间隔,控制时间的函数有以下几种:a)调用函数SetTimer()设置定时间隔,如SetTimer(0,200,NULL)即为设置200毫秒的时间间隔。

b)在应用程序中增加定时响应函数OnTimer(),并在该函数中添加响应的处理语句,用来完成时间到时的操作。

这种定时方法是非常简单的,但其定时功能如同Sleep()函数的延时功能一样,精度较低,只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况,而在精度要求较高的条件下,这种方法应避免采用。

c)精度时控函数,在要求误差不大于1毫秒的情况下,可以采用GetTickCount()函数,该函数的返回值是DWORD型,表示以毫秒为单位的计算机启动后经历的时间间隔。

d)高精度时控函数对于一般的实时控制,使用GetTickCount()函数就可以满足精度要求,但要进一步提高计时精度,就要采用QueryPerformanceFreque ncy()函数和QueryPerformanceCounter()函数。

这两个函数是VC提供的仅供Windows 9X使用的高精度时间函数,并要求计算机从硬件上支持高精度计时器。

接下来就应该考虑如何实现左移,右移,下移,触底,其实很简单就是将屏幕看成一个大的坐标轴,改变坐标的大小,即可控制方块的位置。

销行,就是当一行中全是方块时,即这一行中存储的全是1,就符合销行条件,将这行删除,它之上的所有方块纵坐标下移一格,并且记录销行的次数,以此来控制得分情况,根据所得的分数制定相应的过关规则。

对于如何决定下一个是怎样的方块,可以采用随机数,用随机数来决定的方块。

rand函数是一个随机函数,可以产生从0到rand_max(32767)的随机数,但是每次运行程序产生的随机数都是一样的,这时给随机数产生一个随机种子(seed),函数原型是srand((unsigned)time(NULL));time的值每时每刻都不同。

所以种子不同,所以,产生的随机数也不同。

所以说,要想产生不同的随机数,在使用rand之前需要先调用srandsrand和rand函数都包含在stdlib.h的头文件里。

由于rand产生的随机数是从0到rand_max的,而rand_max(32767)是一个很大的数,那么如何产生从X-Y的数呢?从X到Y,有Y-X+1个数,所以要产生从X到Y的数,只需要这样写:k=rand()%(Y-X+1)+X;这样,就可以产生你想要的任何范围内的随机数了。

2、设计方案。

1)定义一个类class Console来控制窗口的大小,使窗口的大小适合玩家玩游戏。

定义三种静态颜色变量以控制小格子的颜色,使界面更加美观。

static const WORD COLOR_A; // 运动中的颜色static const WORD COLOR_B; // 固定不动的颜色static const WORD COLOR_C; // 空白处的颜色这三种静态变量用户可以自己改变颜色来达到所期望的效果。

需要引入头文件:windows.h下面是一些常用的颜色说明:Attribute MeaningFOREGROUND_BLUE Text color contains blue.FOREGROUND_GREEN Text color contains green.FOREGROUND_RED Text color contains red.FOREGROUND_INTENSITY Text color is intensified.BACKGROUND_BLUE Background color contains blue.BACKGROUND_GREEN Background color contains green.BACKGROUND_RED Background color contains red.BACKGROUND_INTENSITY Background color is intensified.COLOR_A= FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY;//这是运动中的颜色是黄色COLOR_B = FOREGROUND_GREEN;//固定不动的方块颜色是绿色COLOR_C = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE;//空白处的颜色是灰色这是我界面的颜色分布。

2)将屏幕像像素块一样分成11*19的格子,灰色底。

用4*4共16个格子来表示一个方块,用一个4*4的数组来存储七个方块,1代表有一个格子,0代表没有格子,例如:|-,可以用以下数组直观来表示:1000 0100 0100 11101100 1110 1100 01001000 0000 0100 00000000 0000 0000 0000这些数组存储了七种方块,四个变换,于是我定义了一个4维数组bk[7][4][4][4]来存储这些数据,具体见附录2,当在游戏中进行一次旋转就是改变数组最后一维的数值,旋转是逆时针旋转。

以屏幕左上角为原点,从左向右画x轴;从上向下画y轴,(x,y)就代表了在屏幕上的位置,通过控制x,y值来实现左移,右移,上移,下移。

例如向左移的代码如下:void MoveLeft(void) //向左移{if(IsFit(x-1,y,c,z)) //检查是否碰到墙壁{ //没有碰壁则继续VoiceBeep();Draw(COLOR_C); //先将空白处画出--x; //将横坐标减1Draw(COLOR_A); //绘出方块}}判断方块已经到达底部或是否碰到墙壁,“将会”指的是方块如果向左,向右,向下移动后就会碰到障碍物;“障碍物”指的是左右下墙壁和底部已经落下未被消除的小方块。

用下列函数:bool IsFit(int x,int y,int c,int z)//给定的x,y,c,z是否可行{for(int i=0;i<4;++i) //用i,j来遍历16个小格子{for(int j=0;j<4;++j ){if(bk[c][z][i][j]==1){if(y+i<0) continue;//方块还没有落下来//y+i>=19表示已经触底了,x+j<0表示触了最左边的墙,//x+j>=11表示触了最右边的墙,// data[y+i][x+j]==1表示底部已经存在了方块if(y+i>=19||x+j<0||x+j>=11||data[y+i][x+j]==1)return false;}}}return true;}方块落下后,就开始检查是否有满足消除条件的行了。

用char data[19][11] 来记录有小方块存在的地方,有为1,没有事0。

销行的规则很简单:只要某行被小方块全部填充,该行就被消除,上面的小方块全部下移一行。

所以,只要把原来的小方块全部擦去,计算完新方块位置后,再全部画出就可以了,计算的时候,遍历整个游戏区域,看有没有可以消除的行,即遍历char data[19][11]看一行中是否全1,如果是,则开始将这行上面的所有行开始下移,并用int line -count来记录销行的次数,这与之后的计分和关数的计算有关系,销一行加100分,如果有连销行则分数相应增加,每10000分是一个等级,99999封顶。

代码如下:void RemoveRow(void) //消行函数{const char FULLLINE[]={ 1,1,1,1,1,1,1,1,1,1,1};int linecount = 0; //记录连续销行的行数for(int i=0;i<19;++i) //开始对19*11的格子开始遍历{ //如果一行中11列均是1则满足销行条件if(0==memcmp(data[i],FULLLINE,11)){++linecount;for(int m=0;m<11 ++m){for(int n=i;n>1;--n){ //对这行以上的行进行下移,//就是销去了这一行data[n][m]=data[n-1][m];win.Output(2+m*2,1+n,data[n][m]==1?COLOR_B:COLOR_C,"■",2);}data[0][m] = 0; //最顶部赋值为0,既没有小方块 win.Output(2+m*2, 1,COLOR_C,"■",2);}}}char data[19][11]={0};if(linecount==0) return;int _score = 0;switch(linecount) //按照销行的行数来给分数{case 1: _score = 100; break;case 2: _score = 300; break;case 3: _score = 700; break;case 4: _score =1500; break;}score += _score;if(score>99999) score = 99999;//最高分数是99999level = score/10000; //设置等级DrawScoreLevel(); //绘制得分框}3)用Sleep()函数来控制刷图的速度,程序中设定每55ms刷一次图,Sleep(55);用简单Beep(freq,dura)来控制声音,其中freq是频率,dura是持续时间;用随机函数srand(time(0));next=rand()%7来控制下一个方块类型。

相关主题