第二十九节 消除满行

作者: 安静的程序员 | 来源:发表于2019-06-25 09:34 被阅读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

    相关文章

      网友评论

        本文标题:第二十九节 消除满行

        本文链接:https://www.haomeiwen.com/subject/lfbzqctx.html