在上一节中,尽管已经堆叠了一大堆方块,但因为没有消除那些已经填满的行,所以屏幕最终会被填满,游戏就无法继续了。
这一节,我们来消除满行。
01.分析
有两种消除方案:
- 一行行扫描,扫描到满行时,执行消除,然后继续扫描下一行
- 一行行扫描,先记录所有需要消除的行,扫描完成后,执行消除
我选择第二种方案,至于原因,我感觉这样分工更明确。
如何扫描:一行一行扫描,如果在行中遇到空的点,则跳到下一行。如果扫描到了一行中的最后一个点,还没有遇到空的点,就说明该行已经被填满了,将该行的行号记录在需要消除的行中。所有行扫描完成后,扫描结束。
如何消除:遍历需要消除的行,将对应的点从固定方块中移除。
消除完成后,就会出现空行,需要下移空行上面的方块。
02.代码实现
02.01 先为导演添加一个成员,记录需要消除的行号列表:
List<int> _needClearLines; // 记录需要消除的行
然后在初始化游戏方法中初始化此成员:
_needClearLines = new List<int>();
02.02 添加方法,填充需要消除的行:
// 填充需要消除的行
void FillNeedClearLines()
{
for (int line = 0; line < 20; line++)
{
for (int list = 0; list < 10; list++)
{
if (_defaultLayer.IsCanSee(new MyPoint(line, list)))
{
// 如果不是该行的最后一个点,则扫描该行的下一个点
if (list != 9) continue;
// 如果该行的点全都扫描到了,说明该行需要消除
else _needClearLines.Add(line);
}
// 如果扫描到空点,则退出该行的扫描,扫描下一行
else break;
}
}
}
02.03 消除满行
因为需要删除图层中显示数据中的点,所以在图层类中添加一个移除点方法:
// 移除点
public void RemovePoint(int line, int list)
{
int index = 0;
foreach (var point in ViewData)
{
if (point._line == line && point._list == list) break;
index++;
}
ViewData.RemoveAt(index);
}
回到导演类,添加消除满行方法:
// 消除满行
void ClearFullLines()
{
// 遍历行
foreach (var lineNumber in _needClearLines)
{
// 移除该行上所有的点
for (int list = 0; list < 10; list++)
{
_defaultLayer.RemovePoint(lineNumber, list);
}
}
_needClearLines.Clear();
// 刷新屏幕
_screenMain.RefreshScreen();
}
02.04 填补消除后的行
取名是一个非常头疼的工作,要名副其实,而且不能与其他方法名混淆,也不能引起歧义,虽然说可以添加注释,但不能依赖注释,更好的方法名才是我们需要的。
经过一番思索,感觉还是使用“填补消除后的行”更合适,就是感觉太长了,如果你有更好的名字,请留言告诉我。
那么,方法名为:FillUpClearedLine()
填补原理:按从上至下填充,就是说,依次将最顶端的空行上的点下移:
// 填补消除后的行
void FillUpClearedLine()
{
while (_needClearLines.Count > 0)
{
int line = _needClearLines[_needClearLines.Count - 1];
List<MyPoint> fixedPoints = _defaultLayer.ViewData;
for (int index = 0; index < fixedPoints.Count; index++)
{
// 将高于当前行的点下移一格
if (fixedPoints[index]._line > line)
{
fixedPoints[index] = new My-Point(fixedPoints[index]._line - 1, fixedPoints[index]._list);
}
}
_needClearLines.RemoveAt(_needClearLines.Count - 1);
_screenMain.RefreshScreen();
}
}
02.05 在游戏核心逻辑中调用
// 游戏核心逻辑
void GameCore()
{
if (!MoveDownBlock())
{
// 先固定方块
FixActiveBlock();
// 计算需要消除的行
FillNeedClearLines();
// 如有需要消除的行
if (_needClearLines.Count > 0)
{
// 消除行
ClearFullLines();
// 填补消除后的行
FillUpClearedLine();
}
// 创建新方块
CreateNewBlock();
}
}
好了,经过一番折腾,功能终于实现了,不过,目前的消除动作几乎是在一瞬间就完成了,太生硬了,接下来,我们将为其添加一些动画。
代码链接:https://pan.baidu.com/s/1reST9ttihP_u4uQJ0SSwgg
提取码:o5f2
网友评论