手把手教你Unity开发俄罗斯方块

第二十九节 消除满行

2019-06-25  本文已影响0人  安静的程序员

在上一节中,尽管已经堆叠了一大堆方块,但因为没有消除那些已经填满的行,所以屏幕最终会被填满,游戏就无法继续了。
这一节,我们来消除满行。

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

上一篇 下一篇

猜你喜欢

热点阅读