薛 鹏 段华琼*
(四川大学锦城学院 计算机与软件学院,四川 成都611371)
俄罗斯方块最早是由俄罗斯人阿列克谢·帕基特诺夫于1984 年6 月发明的一款经典游戏。俄罗斯方块游戏是在一个固定边界的界面中,不同方块随机出现在上边界,玩家通过键盘上的asd(左下右)以及空格(形状变化)操控,通过控制空格键来改变方块的形状,让方块落到边界的底部。满行的方块将会被消除并且获得相应的分数,如果没有满行则方块的高度会一直往上面叠加,当叠加的方块到达顶端的时候,判定为游戏的结束。
在实现游戏时,需要先用二维数组来绘制地图和显示下一个将会出现方块的边框,并且在这些位置输出来表示墙体,边框那个位置坐标的值赋为1。地图其他位置坐标的初始值赋为0。用一个基类来表示方块的种类,每一种不同的方块都继承该基类。方块的下落过程用方块的坐标位置更新来体现(在新的位置来打印出方块,在原来位置上打印空格,以此实现视觉上方块的移动)。方块的移动用遍历的方式来进行判断,对方块的周围进行遍历,如果不符合遍历的条件,则表示方块不能变形或者移动。玩家通过控制ads 三个键位分别控制方块的左移、右移,使用空格按键来对满足变形条件的方块进行形状的改变。当方块到达最底端的时候将方块坐标位置的值赋为2(不赋为1是因为墙体所在坐标位置的值是1,被固定了的方块坐标所在位置的赋为2 将其与墙体产生区别)。在游戏过程中,玩家通过自己所控制的方块从底部往上面堆积。如果堆积的方块填满了一层,将清除这一层所有的方块并且这一层上面所有的方块向下挪动一个单位。在消除该层方块后将会获得相应分数的增加。每消除一层方块,方块下落的速度将会增加,随着消除方块层数的增加,方块的下落速度会越来越快,以此来提升游戏难度。当新产生的方块下面有堆积的方块时判定为游戏失败,游戏失败后显示存活秒数以及获得的分数。可以将整个俄罗斯方块游戏分为以下三个环节:第一个环节:初始化游戏界面,绘制游戏边框,以及在边框右侧显示第一个将要出现的方块。第二个环节:根据玩家的操作,方块不停的积累或者消除,随着消除方块行数的增加获得的分数也到相应得到增加。每消除一行方块,方块下落速度将会变得更快。第三个环节:随着没有被消除方块的积累,当新出现的方块下面已经有了堆积的方块时,判定游戏结束。显示存活秒数以及获得分数。
该种父类中包含方块的坐标结构体数组,造型类型函数,运动状态检测函数,能否改变形状检测函数,方块的打印与清除函数,检测游戏死亡函数等等。
这个结构体记录了每一个方块的x 坐标以及y 坐标,在方块的基类中用结构体数组来表示四个方块。
这是一个虚函数,因为每个方块的变形方式不同,所以要把这个函数设置为虚函数,避免继承中产生的二义性问题。
这个函数的作用是检测方块的状态,检测方块是否应该被固定,如果下面有其他方块了,那么这个方块就应该被固定了。具体实现是:使用for 循环进行遍历每个方块下面那个位置的值,当检测到当前所有方块中的某一个方格下面的坐标位置处的值不为0 的时候,那么就将这个方块固定。然后将全局变量CreatFangKuai 赋为1,表示可以产生新的方块,以达到可以连续生成新方块的目的。将state 赋为0,代表方块不可移动。再把当前这些方块坐标位置的值修改为2,以便和墙体产生区别。
bool checkCanLeft()检测能否左移,bool checkCanRight()检测右移,bool checkCanDown()检测是否快速下移。
拿左移举例,最开始让bool flag=true,方块最开始默认为可以左移。然后使用循环遍历每个位置的左侧,当有一个方块的左侧不为0(即墙体或者出现其他的方块)时,就不允许左移(if(MapValue[fangKuai[i].x-2][fangKuai[i].y]!=0))。右移与左移类似。注意,此处x+2 的原因是因为每个在x 轴上面占两个宽度。下移则是if(MapValue[fangKuai[i].x][fangKuai[i].y+1]! =0)。值得关注的是:在电脑的坐标系中,往下移动应该是y 轴方向上加1,最左上角是看作为坐标原点,往下方向设为y 轴的正方向,与常规的平面直角坐标系稍有区别。
代表速度的全局变量DownSpeed 的初始值为1,DownSpeed=sumScore/10+1。sumScore 记录游戏分数,使用这个函数可以让方块下落的速度随着游戏分数的提高而提高。从而慢慢的提高游戏的难度。
这个函数的实现是使用双重for 循环,在指定位置上打印出空格符号,从而达到清空指定位置上的方格的目的。
用函数void drawNextFangkuai(int a,int b)实现。需要先使用clearNextFangkuai()函数,清空上一次出现在预测位置的方块。随机传入a,b 两个值。在这个函数中有一个switch 语句,这个语句枚举出每一种可能出现的情况,a 值代表对应方块的种类,b 值代表该种方块的朝向,以此来预测并绘制下一次出现的方块,让玩家提前做好应对策略。
由函数int keydown()实现。这个函数用于接收asd 以及空格四个按键的信息。该函数的作用是:当按键被按下时,发生keydown 事件(或者发生keydown 事件时调用相应的函数)。为了防止有多次无效的输入,所以设计了一个循环,当里面有数据的时候,循环取出,只使用最后一次的输入,具体代码如下:
由函数void gotoXY(int x,int y)实现。传入光标需要移动的目标位置的x 坐标和y 轴坐标即可将光标的位置发生改变。在该程序中光标移动函数的作用非常的大,可以将光标移动到指定的位置处去,需要注意的是,使用这个函数必须包含头文件windows.h。使用这个函数可以很大程度上方便地图的打印工作。
int getRandRange(int min,int max)是一个自定义的函数,内容是return rand()%(max-min+1)+min;可以用这个函数返回一个min 到max 之间的随机整数,以此来模拟下一次随机出现的方块类型。
由函数checkDeath()实现。这个函数用在各个方块类的构造函数里面。具体是实现代码是:if (MapValue [fangKuai[i].x][fangKuai[i].y]! = 0)。如果新的方块刚刚生成时下面就有其他方块则判定游戏失败。它的原理是:将所有积累的方块的坐标处那个位置的值赋为2,待新方块生成后判断新生成方块的位置处的值是否为0,如果不为0 则结束游戏。
论文基于C++语言提供了俄罗斯方块游戏的设计思路和实现方法。程序每个功能都由一个函数具体实现,设置了方块的基类,充分展现了程序的模块化设计和C++中面相对象编程的两种编程思想。通过实践俄罗斯方块游戏的设计与实践,能充分锻炼模块化编程的思想以及加深对C++的理解与掌握。