7.方块变形

  1. 7.方块变形
    1. 7.1 知识点
      1. 主要操作
    2. 7.2 知识点代码
      1. GameScene
      2. DrawObject
      3. Map
      4. BlockWorker

7.方块变形


7.1 知识点

主要操作

  1. 在搬砖工人类实现一些方法。
  2. 声明变形左右枚举,决定顺时针还是逆时针。
  3. 创建当前的形态索引,在随机一个方块方法时替换随机的临时变量形态索引,赋值给当前的形态索引,相当于把当前的形态索引记录下来。
  4. 声明一个变形方法,传入变形左右枚举,算出当前索引。得到索引的目的是通过传入索引得到当前存着的方块信息变量,得到对应形态的,然后得到位置偏移信息,就可以计算将另外的三个小方块的位置算出来。
  5. 测试会发现变形前没有擦除,所以创建用于擦除的方法,遍历搬砖工人手里的方块,擦除方块。
  6. 擦除方块时会发现没有擦除的方法,在绘制对象类实现一个擦除方法,就是设置光标位置写出空字符。
  7. 因为变形的时候可能会和地图上的方块重合,所以要写一个判断能不能变形的方法。在这个方法里模拟变一次,再遍历判断是否超出地图边界或者判断是否和地图上的动态方块重合。
  8. 再变形前加入能否变形的判断。

7.2 知识点代码

GameScene

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

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

        public GameScene()
        {
            map = new Map();
            blockWorker = new BlockWorker();
        }

        public void Update()
        {
            //地图绘制
            map.Draw();
            //搬运工绘制
            blockWorker.Draw();

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

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()
        {
            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()
        {
            Console.SetCursorPosition(pos.x, pos.y);
            Console.Write("  ");
        }
        #endregion

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

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>();

        #region Lesson6 为了外部能快速得到地图边界
        public int w;
        public int h;
        #endregion

        //重载一次无参构造 去初始化我们的固定墙壁
        public Map()
        {
            //为了方便外部得到地图的高的边界 直接在此记录 避免修改代码时多处修改
            h = Game.h - 6;
            for (int i = 0; i < Game.w; i+=2)
            {
                walls.Add(new DrawObject(E_DrawType.Wall, i, h));
            }

            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();
            }
        }

        /// <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]);
            }
        }
    }
}

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

---

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

×

喜欢就点赞,疼爱就打赏