思考并回答以下问题:
- 洪水填充(Flood fill)算法是什么?
游戏规则
- 1.有一块用于摆放方块的平面虚拟场地,其标准大小:行宽为10,列高为20,以一个小方块为一个单位。
- 2.有一组由4个方块组成的规则图形(中文通称为方块),共有7种,分别以I、J、L、S、T、Z、O这7个字母的形状来命名,如图1所示。
俄罗斯方块的7种形状
3.玩家可以进行如下操作。
- 以90度为单位旋转方块;
- 以格子为单位左右移动方块;
- 让方块加速下落。
方块移到区域最下方或者着地到其他方块上无法移动时,就会固定在该处,而新的方块会出现在区域上方开始落下。
4.当区域中的某一行格子全部由方块填满,则该行方块会消失并成为玩家的得分。删除的行越多,得分越高。当方块堆到区域最上方而无法消除时,则该游戏结束。
- 5.一般来说,游戏会提示下一个要落下的方块。
- 6.几种常见的游戏模式如下。
- 经典马拉松:在该模式下游戏无计时,一直到方块组堆到最上方并且无法消除时,游戏结束。
- 竞速模式:消除指定的行数,用时最短者获胜。
- 定时模式:在一定的时间内,得分最高者获胜。
- 重力模式:传统版本的俄罗斯方块将堆栈的块向下移动一段距离,正好等于它们之下清除的行的高度。与重力定律相反,块可以悬空在间隙之上,如图2所示。实现使用洪水填充的不同算法将游戏区域分割成连接的区域将使每个区域并行落下,直到它接触到游戏场底部的区域。这开启了额外的“连锁反应”策略,涉及块级联以填补额外的线路,这可能被认为是更有价值的清除,如图3所示。
图2 传统模式
图3 重力模式下的连锁反应
在本章中,我们实现的是俄罗斯方块的经典马拉松模式。
- 7.降落方式如下。
- 硬降:方块立即下落到最下方并锁定。
- 软降:方块加速下落。
- 8.旋转踢墙:指一个方块即使旋转后重合了左右墙壁或现有方块也有能旋转的能力。在NES(红白机)版本中,如果一个Z竖立着靠着左边的墙壁,玩家就不能旋转这个方块,给人的感觉就像是锁定了一样,在这种情况下,玩家必须在旋转之前把方块组向右移动一格,但就会失去宝贵的时间。
游戏实现思路
随机生成方块
用一个数组存放7种方块组,用生成随机数的方式选择生成方块组形状。
地图的生成
将场景看作是一个10 ×20的二维数组,每一个小方块占1个单位。每个格子在数组中的索引号为这个格子的坐标。
判断方块是否都在边界内
左右移动方块时,获取方块组中每个子方块的坐标以及边界的坐标,进行比较以判断方块组是否在边界内。若在边界内,更新方块组的坐标数据。
1 | for(每个子方块) |
方块组旋转时超出边界的情况,如图4所示。
图4 旋转超出边界
解决办法如下。
- 不能旋转。应该在旋转之后,循环遍历方块组的每一个方块,判断是否都在边界内,若有子方块不在边界内,再反方向旋转回去,这种方式在视觉上看起来就好像方块组被冻结,无法旋转。
- 能够旋转。在旋转后,遍历方块组的所有子方块,如果有方块的位置不在边界内,则将每个子方块的坐标向边界内移动,这种情况被称为旋转踢墙。
判断是否碰到其他方块
循环遍历网格数组,检测方块组要到达的地方是否为空,若为空,则继续移动,更新方块位置的坐标数据,若不为空,则停止移动。
检查是否满行
在地图中,位于同一行的方块的y坐标相同,遍历数组中y坐标相同的数据是否为空。若都不为空,则表示y坐标为y的一行被填满。1
2
3
4
5
6for(int x = 0; x < 宽度; x++)
{
if((x,y)位置上没有方块)
return false;
return true;
}
删除填满的行
删除该行数组的元素,即将数组中该行的数据全部置为空。再遍历上面所有行,将数组中的所有元素的y坐标减1,达到下落的效果。1
2
3
4
5
6
7
8for(int y = 0; y < height;y++)
{
if(高度为Y的一行被填满)
{
删除y行的所有元素;
遍历y行上面所有的行,将上面所有行的Y坐标-1;
}
}
提示下一个方块组
判断是否是第一次生成方块,若是,则产生两个随机数,一个是当前的方块组的编号,一个是下一个方块组的编号;若不是,则将当前的编号置为下一个方块组的编号,再产生一个随机数表示下一个方块组的编号。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16bool isFirst = true;
int currentNum = 0; //当前方块组的编号
int nextNum = 0; //下一个方块组的编号
if(isFirst)
{
currentNum = 方块组数组长度内的一个随机数;
nextNum = 方块组数组长度内的一个随机数;
isFirst = false;
}
else
{
currentNum = nextNum;
nextNum = 方块组数组长度内的一个随机数;
}
产生编号为currentNum的方块组;
绘制编号为nextNum的方块组;
结束判定
获取产生的方块组的坐标,判断方块组中的子方块的坐标是否超过上边界,如果超出上边界,则游戏结束,如果没有超出上边界,则游戏继续。
游戏流程图
如图5所示。
游戏程序实现
Spawner.cs
1 | using System.Collections; |
Group.cs
1 | using System.Collections; |
Grid.cs
1 | using System.Collections; |