14.代码汇总

14.代码汇总


14.1 Program

using System;

namespace CSharp进阶实践教学
{
    class Program
    {
        static void Main(string[] args)
        {
            Game g = new Game();
            g.Start();
        }
    }
}

14.2 Game

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

namespace CSharp进阶实践教学
{
    /// <summary>
    /// 场景类型枚举
    /// </summary>
    enum E_SceneType
    {
        /// <summary>
        /// 开始场景
        /// </summary>
        Begin,
        /// <summary>
        /// 游戏场景
        /// </summary>
        Game,
        /// <summary>
        /// 结束场景
        /// </summary>
        End,
    }

    class Game
    {
        //游戏窗口宽高
        public const int w = 50;
        public const int h = 35;
        //当前选中的场景
        public static ISceneUpdate nowScene;

        public Game()
        {
            Console.CursorVisible = false;
            Console.SetWindowSize(w, h);
            Console.SetBufferSize(w, h);

            ChangeScene(E_SceneType.Begin);
        }

        //游戏开始的方法
        public void Start()
        {
            //游戏主循环 主要负责 游戏场景逻辑的更新
            while (true)
            {
                //判断当前游戏场景不为空 就更新
                if( nowScene != null )
                {
                    nowScene.Update();
                }
            }
        }

        public static void ChangeScene(E_SceneType type)
        {
            //切场景之前 应该把上一个场景的绘制内容擦掉
            Console.Clear();

            switch (type)
            {
                case E_SceneType.Begin:
                    nowScene = new BeginScene();
                    break;
                case E_SceneType.Game:
                    nowScene = new GameScene();
                    break;
                case E_SceneType.End:
                    nowScene = new EndScene();
                    break;
            }
        }
    }
}

14.3 ISceneUpdate

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

namespace CSharp进阶实践教学
{
    
    /// <summary>
    /// 场景更新接口
    /// </summary>
    interface ISceneUpdate
    {
        void Update();
    }
}

14.4 BeginOrEndBaseScene

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

namespace CSharp进阶实践教学
{
    abstract class BeginOrEndBaseScene : ISceneUpdate
    {
        protected int nowSelIndex = 0;
        protected string strTitle;
        protected string strOne;

        public abstract void EnterJDoSomthing();

        public void Update()
        {
            //开始和结束场景的 游戏逻辑 
            //选择当前的选项 然后 监听 键盘输入 wsj
            Console.ForegroundColor = ConsoleColor.White;
            //显示标题
            Console.SetCursorPosition(Game.w / 2 - strTitle.Length, 5);
            Console.Write(strTitle);
            //显示下方的选项
            Console.SetCursorPosition(Game.w / 2 - strOne.Length, 8);
            Console.ForegroundColor = nowSelIndex == 0 ? ConsoleColor.Red : ConsoleColor.White;
            Console.Write(strOne);
            Console.SetCursorPosition(Game.w / 2 - 4, 10);
            Console.ForegroundColor = nowSelIndex == 1 ? ConsoleColor.Red : ConsoleColor.White;
            Console.Write("结束游戏");
            //检测输入
            switch (Console.ReadKey(true).Key)
            {
                case ConsoleKey.W:
                    --nowSelIndex;
                    if (nowSelIndex < 0)
                    {
                        nowSelIndex = 0;
                    }
                    break;
                case ConsoleKey.S:
                    ++nowSelIndex;
                    if (nowSelIndex > 1)
                    {
                        nowSelIndex = 1;
                    }
                    break;
                case ConsoleKey.J:
                    EnterJDoSomthing();
                    break;
            }
        }
    }
}

14.5 BeginScene

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

namespace CSharp进阶实践教学
{
    class BeginScene : BeginOrEndBaseScene
    {
        public BeginScene()
        {
            strTitle = "俄罗斯方块";
            strOne = "开始游戏";
        }

        public override void EnterJDoSomthing()
        {
            //按J键做什么的逻辑
            if (nowSelIndex == 0)
            {
                Game.ChangeScene(E_SceneType.Game);
            }
            else
            {
                Environment.Exit(0);
            }
        }
    }
}

14.6 EndScene

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

namespace CSharp进阶实践教学
{
    class EndScene : BeginOrEndBaseScene
    {
        public EndScene()
        {
            strTitle = "结束游戏";
            strOne = "回到开始界面";
        }

        public override void EnterJDoSomthing()
        {
            //按J键做什么的逻辑
            if (nowSelIndex == 0)
            {
                Game.ChangeScene(E_SceneType.Begin);
            }
            else
            {
                Environment.Exit(0);
            }
        }
    }
}

14.7 GameScene

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

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

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

            //添加输入事件监听
            InputThread.Instance.inputEvent += CheckInputThread;

            //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

        /// <summary>
        /// 停止线程
        /// </summary>
        public void StopThread()
        {
            //isRunning = false;
            //inputThread = null;

            //移除输入事件监听
            InputThread.Instance.inputEvent -= CheckInputThread;

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

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

14.8 IDraw

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

namespace CSharp进阶实践教学
{
    interface IDraw
    {
        void Draw();
    }
}

14.9 Position

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

namespace CSharp进阶实践教学
{
    struct Position
    {
        public int x;
        public int y;

        public Position(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        //肯定是存在比较相关的信息的
        public static bool operator ==(Position p1, Position p2)
        {
            if (p1.x == p2.x && p1.y == p2.y)
                return true;
            return false;
        }

        public static bool operator !=(Position p1, Position p2)
        {
            if (p1.x == p2.x && p1.y == p2.y)
                return false;
            return true;
        }

        public static Position operator +(Position p1, Position p2)
        {
            Position pos = new Position(p1.x + p2.x, p1.y + p2.y);
            return pos;
        }
    }
}

14.10 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;
        }
    }
}

14.11 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

    }
}

14.12 BlockInfo

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

namespace CSharp进阶实践教学
{
    class BlockInfo
    {
        //方块信息坐标的容器
        private List<Position[]> list;

        public BlockInfo(E_DrawType type)
        {
            //必须要初始化才能往里面装东西
            list = new List<Position[]>();

            switch (type)
            {
                case E_DrawType.Cube:
                    //添加了一个形状的位置信息
                    list.Add(new Position[3] {
                        new Position(2,0),
                        new Position(0,1),
                        new Position(2,1)
                    });
                    break;
                case E_DrawType.Line:
                    //初始化 长条形状的4种形态的坐标信息
                    list.Add(new Position[3] {
                        new Position(0,-1),
                        new Position(0,1),
                        new Position(0,2)
                    });
                    list.Add(new Position[3] {
                        new Position(-4,0),
                        new Position(-2,0),
                        new Position(2,0)
                    });
                    list.Add(new Position[3] {
                        new Position(0,-2),
                        new Position(0,-1),
                        new Position(0,1)
                    });
                    list.Add(new Position[3] {
                        new Position(-2,0),
                        new Position(2,0),
                        new Position(4,0)
                    });
                    break;
                case E_DrawType.Tank:
                    list.Add(new Position[3] {
                        new Position(-2,0),
                        new Position(2,0),
                        new Position(0,1)
                    });
                    list.Add(new Position[3] {
                        new Position(0,-1),
                        new Position(-2,0),
                        new Position(0,1)
                    });
                    list.Add(new Position[3] {
                        new Position(0,-1),
                        new Position(-2,0),
                        new Position(2,0)
                    });
                    list.Add(new Position[3] {
                        new Position(0,-1),
                        new Position(2,0),
                        new Position(0,1)
                    });
                    break;
                case E_DrawType.Left_Ladder:
                    list.Add(new Position[3]{
                        new Position(0,-1),
                        new Position(2,0),
                        new Position(2,1)
                    });
                    list.Add(new Position[3]{
                        new Position(2,0),
                        new Position(0,1),
                        new Position(-2,1)
                    });
                    list.Add(new Position[3]{
                       new Position(-2,-1),
                        new Position(-2,0),
                        new Position(0,1)
                    });
                    list.Add(new Position[3]{
                        new Position(0,-1),
                        new Position(2,-1),
                        new Position(-2,0)
                    });
                    break;
                case E_DrawType.Right_Ladder:
                    list.Add(new Position[3]{
                        new Position(0,-1),
                        new Position(-2,0),
                        new Position(-2,1)
                    });
                    list.Add(new Position[3]{
                        new Position(-2,-1),
                        new Position(0,-1),
                        new Position(2,0)
                    });
                    list.Add(new Position[3]{
                        new Position(2,-1),
                        new Position(2,0),
                        new Position(0,1)
                    });
                    list.Add(new Position[3]{
                        new Position(0,1),
                        new Position(2,1),
                        new Position(-2,0)
                    });
                    break;
                case E_DrawType.Left_Long_Ladder:
                    list.Add(new Position[3]{
                        new Position(-2,-1),
                        new Position(0,-1),
                        new Position(0,1)
                    });
                    list.Add(new Position[3]{
                        new Position(2,-1),
                        new Position(-2,0),
                        new Position(2,0)
                    });
                    list.Add(new Position[3]{
                        new Position(0,-1),
                        new Position(2,1),
                        new Position(0,1)
                    });
                    list.Add(new Position[3]{
                        new Position(2,0),
                        new Position(-2,0),
                        new Position(-2,1)
                    });
                    break;
                case E_DrawType.Right_Long_Ladder:
                    list.Add(new Position[3]{
                        new Position(0,-1),
                        new Position(0,1),
                        new Position(2,-1)
                    });
                    list.Add(new Position[3]{
                        new Position(2,0),
                        new Position(-2,0),
                        new Position(2,1)
                    });
                    list.Add(new Position[3]{
                        new Position(0,-1),
                        new Position(-2,1),
                        new Position(0,1)
                    });
                    list.Add(new Position[3]{
                        new Position(-2,-1),
                        new Position(-2,0),
                        new Position(2,0)
                    });
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 提供给外部根据索引快速获取 位置偏移信息的
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Position[] this[int index]
        {
            get
            {
                if (index < 0)
                    return list[0];
                else if (index >= list.Count)
                    return list[list.Count - 1];
                else
                    return list[index];
            }
        }

        /// <summary>
        /// 提供给外部 获取 形态有几种
        /// </summary>
        public int Count { get => list.Count; }

    }
}

14.13 BlockWorker

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

namespace CSharp进阶实践教学
{
    /// <summary>
    /// 变形左右枚举 决定顺时针还是逆时针
    /// </summary>
    enum E_Change_Type
    {
        Left,
        Right,
    }

    class BlockWorker : IDraw
    {
        //方块们
        private List<DrawObject> blocks;
        //心中要默默的知道 各个形状的方块信息是什么
        //选择一个容器来纪录各个方块的形态信息
        //用list和Dictionary都可以用来存储方块的几种信息
        //我们选择Dictionary的主要目的是好找 并且起到练习的作用
        private Dictionary<E_DrawType, BlockInfo> blockInfoDic;
        //记录随机创建出来的方块的 具体形态信息
        private BlockInfo nowBlockInfo;
        //当前的形态索引
        private int nowInfoIndex;

        public BlockWorker()
        {
            //初始化 装块信息 
            blockInfoDic = new Dictionary<E_DrawType, BlockInfo>()
            {
                { E_DrawType.Cube, new BlockInfo(E_DrawType.Cube) },
                { E_DrawType.Line, new BlockInfo(E_DrawType.Line) },
                { E_DrawType.Tank, new BlockInfo(E_DrawType.Tank) },
                { E_DrawType.Left_Ladder, new BlockInfo(E_DrawType.Left_Ladder) },
                { E_DrawType.Right_Ladder, new BlockInfo(E_DrawType.Right_Ladder) },
                { E_DrawType.Left_Long_Ladder, new BlockInfo(E_DrawType.Left_Long_Ladder) },
                { E_DrawType.Right_Long_Ladder, new BlockInfo(E_DrawType.Right_Long_Ladder) },
            };

            //随机方块
            RandomCreateBlock();
        }

        public void Draw()
        {
            for (int i = 0; i < blocks.Count; i++)
            {
                blocks[i].Draw();
            }
        }

        /// <summary>
        /// 随机创建一个方块
        /// </summary>
        public void RandomCreateBlock()
        {
            //随机方块类型
            Random r = new Random();
            E_DrawType type = (E_DrawType)r.Next(1, 8);
            //每次新建一个 砖块 其实就是创建4个小方形
            blocks = new List<DrawObject>()
            {
                new DrawObject(type),
                new DrawObject(type),
                new DrawObject(type),
                new DrawObject(type),
            };
            //需要初始化方块位置
            //原点位置 我们随机 自己定义 方块List中第0个就是我们的原点方块
            blocks[0].pos = new Position(24, -5);
            //其它三个方块的位置
            //取出方块的形态信息 来进行具体的随机
            //应该把取出来的 方块具体的形态信息 存起来 用于之后变形
            nowBlockInfo = blockInfoDic[type];
            //随机几种形态中的一种来设置方块的信息吧
            nowInfoIndex = r.Next(0, nowBlockInfo.Count);
            //取出其中一种形态的坐标信息
            Position[] pos = nowBlockInfo[nowInfoIndex];
            //讲另外的三个小方块进行设置 计算
            for (int i = 0; i < pos.Length; i++)
            {
                //取出来的pos是相对原点方块的坐标 所以需要进行计算
                blocks[i + 1].pos = blocks[0].pos + pos[i];
            }
        }

        #region Lesson6 变形相关方法
        //擦除的方法
        public void ClearDraw()
        {
            for (int i = 0; i < blocks.Count; i++)
            {
                blocks[i].ClearDraw();
            }
        }

        /// <summary>
        /// 变形
        /// </summary>
        /// <param name="type">左边还是右边</param>
        public void Change(E_Change_Type type)
        {
            //变之前把之前的位置擦除
            ClearDraw();

            switch (type)
            {
                case E_Change_Type.Left:
                    --nowInfoIndex;
                    if (nowInfoIndex < 0)
                        nowInfoIndex = nowBlockInfo.Count - 1;
                    break;
                case E_Change_Type.Right:
                    ++nowInfoIndex;
                    if (nowInfoIndex >= nowBlockInfo.Count)
                        nowInfoIndex = 0;
                    break;
            }
            //得到索引目的 是得到对应形态的 位置偏移信息
            //用于设置另外的三个小方块
            Position[] pos = nowBlockInfo[nowInfoIndex];
            //将另外的三个小方块进行设置 计算
            for (int i = 0; i < pos.Length; i++)
            {
                //取出来的pos是相对原点方块的坐标 所以需要进行计算
                blocks[i + 1].pos = blocks[0].pos + pos[i];
            }

            //变之后再来绘制
            Draw();
        }

        /// <summary>
        /// 判断是否可以进行变形
        /// </summary>
        /// <param name="type">变形方向</param>
        /// <param name="map">地图信息</param>
        /// <returns></returns>
        public bool CanChange(E_Change_Type type, Map map)
        {
            //用一个临时变量记录 当前索引 不变化当前索引
            //变化这个临时变量
            int nowIndex = nowInfoIndex;

            switch (type)
            {
                case E_Change_Type.Left:
                    --nowIndex;
                    if (nowIndex < 0)
                        nowIndex = nowBlockInfo.Count - 1;
                    break;
                case E_Change_Type.Right:
                    ++nowIndex;
                    if (nowIndex >= nowBlockInfo.Count)
                        nowIndex = 0;
                    break;
            }
            //通过临时索引 取出形态信息 用于重合判断
            Position[] nowPos = nowBlockInfo[nowIndex];
            //判断是否超出地图边界
            Position tempPos;
            for (int i = 0; i < nowPos.Length; i++)
            {
                tempPos = blocks[0].pos + nowPos[i];
                //判断左右边界 和 下边界
                if (tempPos.x < 2 ||
                    tempPos.x >= Game.w - 2 ||
                    tempPos.y >= map.h)
                {
                    return false;
                }
            }
            //判断是否和地图上的动态方块重合
            for (int i = 0; i < nowPos.Length; i++)
            {
                tempPos = blocks[0].pos + nowPos[i];
                for (int j = 0; j < map.dynamicWalls.Count; j++)
                {
                    if (tempPos == map.dynamicWalls[j].pos)
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        #endregion

        #region Lesson7 方块左右移动

        /// <summary>
        /// 左右移动的函数 
        /// </summary>
        /// <param name="type">左或者右</param>
        public void MoveRL(E_Change_Type type)
        {
            //在动之前 要得到原来的坐标 进行擦除
            ClearDraw();

            //根据传入的类型 决定左动还是右动
            //左动 x-2,y0  右动x 2 y 0
            //得到我们的便宜位置
            Position movePos = new Position(type == E_Change_Type.Left ? -2 : 2, 0);
            //遍历我的所有小方块
            for (int i = 0; i < blocks.Count; i++)
            {
                blocks[i].pos += movePos;
            }

            //动之后 再画上去
            Draw();
        }

        /// <summary>
        /// 移动之前判断 判断是否可以进行左右移动
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public bool CanMoveRL(E_Change_Type type, Map map)
        {
            //根据传入的类型 决定左动还是右动
            //左动 x-2,y0  右动x 2 y 0
            //得到我们的便宜位置
            Position movePos = new Position(type == E_Change_Type.Left ? -2 : 2, 0);

            //要不和左右边界重合
            //动过后的结果 不能直接改小方块的位置 改了就覆水难收
            //这只是想预判断 所以 得一个临时变量用于判断即可
            Position pos;
            for (int i = 0; i < blocks.Count; i++)
            {
                pos = blocks[i].pos + movePos;
                if (pos.x < 2 || pos.x >= Game.w - 2)
                    return false;
            }

            //要不和动态方块重合了
            for (int i = 0; i < blocks.Count; i++)
            {
                pos = blocks[i].pos + movePos;
                for (int j = 0; j < map.dynamicWalls.Count; j++)
                {
                    if (pos == map.dynamicWalls[j].pos)
                        return false;
                }
            }
            return true;
        }

        #endregion

        #region Lesson8 方块自动向下移动

        /// <summary>
        /// 自动移动的方法
        /// </summary>
        public void AutoMove()
        {
            //变位置之前擦除
            ClearDraw();

            //首要要得到移动的多少
            //Position downMove = new Position(0, 1);
            //得到所有的方块 让其向下移动
            for (int i = 0; i < blocks.Count; i++)
            {
                //blocks[i].pos += downMove;
                blocks[i].pos.y += 1;
            }

            //变了位置再画
            Draw();
        }

        public bool CanMove(Map map)
        {
            //用临时变量存储 下一次移动的位置 然后用于进行重合判断
            Position movePos = new Position(0, 1);
            Position pos;
            //边界
            for (int i = 0; i < blocks.Count; i++)
            {
                pos = blocks[i].pos + movePos;
                if (pos.y >= map.h)
                {
                    //停下来 给予地图动态方块
                    map.AddWalls(blocks);
                    //随机创建新的方块
                    RandomCreateBlock();
                    return false;
                }
            }
            //动态方块
            for (int i = 0; i < blocks.Count; i++)
            {
                pos = blocks[i].pos + movePos;
                for (int j = 0; j < map.dynamicWalls.Count; j++)
                {
                    if (pos == map.dynamicWalls[j].pos)
                    {
                        //停下来 给予地图动态方块
                        map.AddWalls(blocks);
                        //随机创建新的方块
                        RandomCreateBlock();
                        return false;
                    }
                }
            }

            return true;
        }
        #endregion
    }
}

14.14 InputThread

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

namespace CSharp进阶实践教学
{
    class InputThread
    {
        //线程成员变量
        Thread inputThread;
        //输入检测事件
        public event Action inputEvent;

        private static InputThread instance = new InputThread();

        public static InputThread Instance
        {
            get
            {
                return instance;
            }
        }

        private InputThread()
        {
            inputThread = new Thread(InputCheck);
            inputThread.IsBackground = true;
            inputThread.Start();
        }

        private void InputCheck()
        {
            while (true)
            {
                inputEvent?.Invoke();
            }
        }
    }
}


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

×

喜欢就点赞,疼爱就打赏