一个简单的用C语言写的俄罗斯方块程序?
有19种俄罗斯方块形状* * *。如果用数组表示,可能会浪费空间(网上有很多实现代码)。
考虑到每个正方形形状都是一个范围为4 *4的小正方形,所以以字体点阵的形式存储,即设置一个4行4列的数组,元素设置为1,表示这个位置小。
Box,元素设置为0,表示这个位置没有小盒子。这整个4*4的阵列形成了俄罗斯方块的形状。?
1000?
1000?
1100?
0000?
上面的4*4代表一个L型的正方形。?
4*4 =16位是短类型,所以每个块可以用一个短类型的数据来表示。
我们将俄罗斯方块点阵的数字存储在rockArray中,可以预先将这19个方块的字体点阵转换成十六进制,然后在初始化rockArray时进行赋值。?
但是这种方法不具有可扩展性,每次有新的方块出现都需要改变。
所以你可以写一个配置文件来表示19种方块。(RockShape.ini)
@###@###@@######1234
从配置文件中读取块类型的代码在下面3中解释(在Init.h的ReadRock函数中)。
2如何画正方形?
您可以使用EasyX库来绘制简单的图形。
EasyX库是在VC下实现TC简单绘图功能的库,简单易学(直接百度EasyX库,里面有详细教程)。
那么如何画一个盒子,这个盒子已经以短式存储了?
从short读取,可以用mask mask = 1与short的每一位进行相位,如果结果是1,则画一个小方块;?
函数声明:
void DisplayRock(int rockIdx,?RockLocation_t*?LocatePtr,bool displayed)1
参数1:表示数组中的下标,取出短类型的盒子表示数据?
参数2:表示当前坐标,即盒子左上角的坐标x,y。
参数3: true表示画方框,false表示擦除方框。
//图形窗口中方框的位置(即定位4*4块的左上角坐标)?typedef结构定位
{ int leftint top
} rock location _ t;123456
3如何翻转同类型的盒子,
按↑的时候应该会翻转同类型的盒子。
例如下横杆和垂直杆。
@###@###@###@###@@@@############****1234567891011
你能想象一个静态循环链表这样实现吗?
循环相同类型的块,
正方形由struct结构表示。
typedef结构岩石
{//用来表示一个盒子的形状(每个字节8位,每4位表示盒子中的一行)。
无符号短rockShapeBitsint?nextRockIndex?//下一个框,数组中的下标?} RockType123456
定义一个RockType类型的数组存储19种方块?
rock type rock array[19]= {(0,0)};
当我们按“↑”时,可以将传入的绘图框函数中的rockIndex改为当前框结构中的nextRockIndex。
简单解释一下ReadRock函数的实现:当读取一个空行时,表示已经读取了一个框,而当读取* * *?行表示已经读取了相同类型的框,这取决于代码实现和代码中的特定注释。
4.主游戏实现逻辑
为什么不贴个预告?
注:上面预览的游戏控制区和游戏显示区是通过Draw.h的DrawGameWindow()函数实现的
(1)在初始位置画一个正方形,在预览区画下一个正方形?
(2)盒子有两种行为:响应键盘命令UserHitKeyBoard()和自由下落?
如果你敲击键盘(w,a,s,d,),空格表示暂停。如果在规定时间内没有敲击键盘,盒子自由下落一个单位。
If (kbhit()) //如果敲击键盘,处理按键。
{
user hit = getch();
用户点击键盘(用户点击& ampcurRockIndex & amp;curRockLocation);
}//如果不是,自动下移一个单位:else不能用,因为键可能不是上、下、左、右。
DWORD new time = GetTickCount();if(new time-old time & gt;=(无符号整数)(300)amp;& ampmoveAbled == TRUE)
{
oldtime = newtime
display rock(curRockIndex & amp;curRockLocation,false);
currocklocation . top+= ROCK _ SQUARE _ WIDTH;//删除一个网格
}1234567891011121314
(3)方块落地时(即不能下移),判断是否满,满则淘汰,然后判断游戏是否结束。如果游戏结束,直接退出游戏。
判断FullLine: fullline()函数,从底线开始判断,直到遇到空行。
而(数!= xROCK_SQUARE_NUM) //遇到空行14。
{
linefull = truecount = 0;for(int I = 1;我& lt= xROCK _ SQUARE _ NUM++i)
{ if (game_board[idx][i] == 0)
{
linefull = falsecount++;
}
} if (linefull) //全行,消除当前行,更新分数。
{
DelCurLine(idx);//消除整行
game _ socres+= 3;
update socres(game _ socres);
idx++;//因为下面会减1。
}
idx-;
}123456789101112131415161718192021
(4)淘汰全线?
把要删除的整行擦掉:也就是块成和背景一样的颜色,码成黑色?
然后把顶行下移,移一行删一行,直到遇到空行?
具体实现见代码game.h?
void DelCurLine(int rowIdx)
(4)判断框是否可以移动?
在game.h中实现
bool MoveAble(int rockIndex,rock location _ t * currentlocatoptr,int f_direction)1
* *对比当前位置(左上角)的坐标,可以放下rockIndex框吗??
注意:如果f_direction是↑,则传入的rockIndex是下一个框* *。
如果不能移动,为game_board设置一个标志,表示位置被占用。
//全局变量——游戏棋盘的状态描述(即表示当前界面哪里有方块)?//0表示否,1表示是(多加两行两列形成栅栏,方便判断盒子是否可以移动)?int game _ board[yROCK _ SQUARE _ NUM+2][xROCK _ SQUARE _ NUM+2]= { 0 };123
实施过程中遇到的一些问题
(1)快速下落时,箱子可能会落在围栏范围之外。
快速下落是让箱子一次下落2个单位距离。?
当判断不能落下时,从当前坐标的顶端减去一个单位的距离,即y。
(2)多线满时,不能消除。
判断满行时,循环寻找满行,找到一个满行,再排除一行,然后继续判断是否满,直到遇到一个空行。