12.结束流程

  1. 12.结束流程
    1. 12.1 知识点
      1. 主要操作
    2. 12.2 知识点代码
      1. Map
      2. GameScene
      3. DrawObject

12.结束流程


12.1 知识点

主要操作

  1. 发现随机创建的方块有可能一出来就重合,所以将随机生成的方块的 y 的位置往上移。

  2. 在屏幕外就写死不绘制和不擦除。

  3. 只要在动态墙壁添加处发现位置顶满,就结束,切换到结束界面。

  4. 在结束界面发现输入还能进行,因为输入线程没有停止,所以要加个标识控制输入线程的关闭。

  5. 在游戏场景类中编写一个关闭线程的方法,让标识为 false 即可。

  6. 在地图类的构造函数中传入游戏场景,切换场景时调用游戏场景停止线程的方法。

  7. 同时发现切完场景直接 break 的话后面的绘制方法还会走完,将 break 改成 return 即可。


12.2 知识点代码

Map

using System;
using System.Collections.Generic;
using System.Text;

namespace CSharp实践教学
{
    class Map : IDraw
    {
        //必须要初始化才能往里面装东西
        //固定墙壁
        private List<DrawObject> walls = new List<DrawObject>();
        //必须要初始化才能往里面装东西
        //动态墙壁
        public List<DrawObject> dynamicWalls = new List<DrawObject>();

        private GameScene nowGameScene;

        #region Lesson6 为了外部能快速得到地图边界
        //动态墙壁的宽容量 一行可以有多少个
        public int w;
        public int h;
        #endregion

        #region Lesson11 跨层
        //记录每一行有多少个小方块的容器
        //索引对应的就是行号
        private int[] recordInfo;
        #endregion

        //重载一次无参构造 去初始化我们的固定墙壁
        public Map( GameScene scene)
        {
            this.nowGameScene = scene;

            //为了方便外部得到地图的高的边界 直接在此记录 避免修改代码时多处修改
            h = Game.h - 6;
            //这个就代表对应每行的计数初始化 默认都为0
            //0~Game.h-7
            recordInfo = new int[h];

            w = 0;
            //在绘制 横向的固定墙壁
            for (int i = 0; i < Game.w; i+=2)
            {
                walls.Add(new DrawObject(E_DrawType.Wall, i, h));
                ++w;
            }
            w -= 2;

            for (int i = 0; i < h; i++)
            {
                walls.Add(new DrawObject(E_DrawType.Wall, 0, i));
                walls.Add(new DrawObject(E_DrawType.Wall, Game.w - 2, i));
            }
        }

        public void Draw()
        {
            //绘制固定墙壁
            for (int i = 0; i < walls.Count; i++)
            {
                walls[i].Draw();
            }

            //绘制动态墙壁 有才绘制
            for (int i = 0; i < dynamicWalls.Count; i++)
            {
                dynamicWalls[i].Draw();
            }
        }

        //清楚动态墙壁
        public void ClearDraw()
        {
            //绘制动态墙壁 有才绘制
            for (int i = 0; i < dynamicWalls.Count; i++)
            {
                dynamicWalls[i].ClearDraw();
            }
        }
        /// <summary>
        /// 提供给外部添加动态方块的函数
        /// </summary>
        /// <param name="walls"></param>
        public void AddWalls( List<DrawObject> walls )
        {
            for (int i = 0; i < walls.Count; i++)
            {
                //传递方块进来时 把其类型改成 墙壁类型
                walls[i].ChangeType(E_DrawType.Wall);
                dynamicWalls.Add(walls[i]);

                //在动态墙壁添加处 发现 位置顶满了 就结束
                if( walls[i].pos.y <= 0 )
                {
                    //关闭输入线程
                    this.nowGameScene.StopThread();
                    //场景切换 切换到结束界面
                    Game.ChangeScene(E_SceneType.End);
                    return;
                }
                //进行添加动态墙壁的计数
                //根据索引来得到行
                //h 是 Game.h - 6
                //y 最大为 Game.h - 7
                recordInfo[h - 1 - walls[i].pos.y] += 1;
            }

            //先把之前的动态小方块擦掉
            ClearDraw();
            //检测移除
            CheckClear();
            //再绘制动态小方块
            Draw();
        }

        #region Lesson11 跨层
        /// <summary>
        /// 检测是否跨层
        /// </summary>
        public void CheckClear()
        {
            List<DrawObject> delList = new List<DrawObject>();
            //要选择记录行中有多少个方块的容器
            //数组
            //判断这个一行是否满(方块)
            //遍历数组 检测数组里面存的数
            //是不是w-2
            for (int i = 0; i < recordInfo.Length; i++)
            {
                //必须满足条件 才证明满了
                //小方块计数 == w(这个w已经是去掉了左右两边的固定墙壁)
                if (recordInfo[i] == w)
                {
                    //1.这一行的所有小方块移除
                    for (int j = 0; j < dynamicWalls.Count; j++)
                    {
                        //当前通过动态方块的y计算它在哪一行 如果行号
                        //和当前记录索引一致 就证明 应该移除
                        if (i == h - 1 - dynamicWalls[j].pos.y)
                        {
                            //移除这个方块 为了安全移除 添加一个记录列表
                            delList.Add(dynamicWalls[j]);
                        }
                        //2.要这一行之上的所有小方块下移一个单位
                        //如果当前的这个位置 是该行以上 那就该小方块 下移一格
                        else if (h - 1 - dynamicWalls[j].pos.y > i)
                        {
                            ++dynamicWalls[j].pos.y;
                        }
                    }
                    //移除待删除的小方块
                    for (int j = 0; j < delList.Count; j++)
                    {
                        dynamicWalls.Remove(delList[j]);
                    }

                    //3.记录小方块数量的数组从上到下迁移
                    for (int j = i; j < recordInfo.Length - 1; j++)
                    {
                        recordInfo[j] = recordInfo[j + 1];
                    }
                    //置空最顶的计数
                    recordInfo[recordInfo.Length - 1] = 0;

                    //跨掉一行后 再次去从头检测是否跨层
                    CheckClear();
                    break;
                }
            }
        }
        #endregion

    }
}

GameScene

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace CSharp实践教学
{
    class GameScene : ISceneUpdate
    {
        Map map;
        BlockWorker blockWorker;

        bool isRunning;

        #region Lesson10 输入线程
        Thread inputThread;
        #endregion
        public GameScene()
        {
            map = new Map(this);
            blockWorker = new BlockWorker();
            #region Lesson10 输入线程

            isRunning = true;
            inputThread = new Thread(CheckInputThread);
            //设置成后台线程 声明周期随主线程决定
            inputThread.IsBackground = true;
            //开启线程
            inputThread.Start();
            #endregion
        }

        #region Lesson10 输入线程
        private void CheckInputThread()
        {
            while (isRunning)
            {
                if (Console.KeyAvailable)
                {
                    //为了避免影响主线程 在输入后加锁
                    lock (blockWorker)
                    {
                        switch (Console.ReadKey(true).Key)
                        {
                            case ConsoleKey.LeftArrow:
                                //判断能不能变形
                                if (blockWorker.CanChange(E_Change_Type.Left, map))
                                    blockWorker.Change(E_Change_Type.Left);
                                break;
                            case ConsoleKey.RightArrow:
                                //判断能不能变形
                                if (blockWorker.CanChange(E_Change_Type.Right, map))
                                    blockWorker.Change(E_Change_Type.Right);
                                break;
                            case ConsoleKey.A:
                                if (blockWorker.CanMoveRL(E_Change_Type.Left, map))
                                    blockWorker.MoveRL(E_Change_Type.Left);
                                break;
                            case ConsoleKey.D:
                                if (blockWorker.CanMoveRL(E_Change_Type.Right, map))
                                    blockWorker.MoveRL(E_Change_Type.Right);
                                break;
                            case ConsoleKey.S:
                                //向下动
                                if (blockWorker.CanMove(map))
                                    blockWorker.AutoMove();
                                break;
                        }
                    }

                }
            }
        }
        #endregion

        public void StopThread()
        {
            isRunning = false;
            inputThread = null;

            //在某些c#版本中 会直接报错 没用
            //inputThread.Abort();
        }

        public void Update()
        {
            //锁里面不要包含 休眠 不然会影响别人
            lock(blockWorker)
            {
                //地图绘制
                map.Draw();
                //搬运工绘制
                blockWorker.Draw();
                //自动向下移动
                if (blockWorker.CanMove(map))
                    blockWorker.AutoMove();
            }
            //用线程休眠的形式 
            Thread.Sleep(200);
        }
    }
}

DrawObject

using System;
using System.Collections.Generic;
using System.Text;

namespace CSharp实践教学
{
    /// <summary>
    /// 绘制类型 根据不同类型 改变绘制的方块的颜色
    /// </summary>
    enum E_DrawType
    {
        /// <summary>
        /// 墙壁
        /// </summary>
        Wall,
        /// <summary>
        /// 正方形方块
        /// </summary>
        Cube,
        /// <summary>
        /// 直线
        /// </summary>
        Line,
        /// <summary>
        /// 坦克
        /// </summary>
        Tank,
        /// <summary>
        /// 左梯子
        /// </summary>
        Left_Ladder,
        /// <summary>
        /// 右梯子
        /// </summary>
        Right_Ladder,
        /// <summary>
        /// 左长梯子
        /// </summary>
        Left_Long_Ladder,
        /// <summary>
        /// 右长梯子
        /// </summary>
        Right_Long_Ladder,
    }

    class DrawObject : IDraw
    {
        public Position pos;

        public E_DrawType type;

        public DrawObject(E_DrawType type)
        {
            this.type = type;
        }

        public DrawObject(E_DrawType type, int x, int y):this(type)
        {
            this.pos = new Position(x, y);
        }

        public void Draw()
        {
            //屏幕外不用再绘制
            if (pos.y < 0)
                return;

            Console.SetCursorPosition(pos.x, pos.y);

            switch (type)
            {
                case E_DrawType.Wall:
                    Console.ForegroundColor = ConsoleColor.Red;
                    break;
                case E_DrawType.Cube:
                    Console.ForegroundColor = ConsoleColor.Blue;
                    break;
                case E_DrawType.Line:
                    Console.ForegroundColor = ConsoleColor.Green;
                    break;
                case E_DrawType.Tank:
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    break;
                case E_DrawType.Left_Ladder:
                case E_DrawType.Right_Ladder:
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    break;
                case E_DrawType.Left_Long_Ladder:
                case E_DrawType.Right_Long_Ladder:
                    Console.ForegroundColor = ConsoleColor.DarkGray;
                    break;
            }
            Console.Write("■");
        }

        #region Lesson6 添加一个清楚绘制的方法
        public void ClearDraw()
        {
            //屏幕外不用再绘制
            if (pos.y < 0)
                return;
            Console.SetCursorPosition(pos.x, pos.y);
            Console.Write("  ");
        }
        #endregion

        /// <summary>
        /// 这是切换方块类型 主要用于搬砖下落到地图时 把搬砖类型编程墙壁类型
        /// </summary>
        /// <param name="type"></param>
        public void ChangeType(E_DrawType type)
        {
            this.type = type;
        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏