俄罗斯方块
文章目录
- Test1_场景切换相关
- BeginScene.cs
- BegionOrEndScene.cs
- EndScene.cs
- Game.cs
- GameScene.cs
- ISceneUpdate.cs
- Test2_绘制对象基类和枚举信息
- DrawObject.cs
- IDraw.cs
- Position.cs
- Test3_地图相关
- Map.cs
- Test4_坐标信息类
- BlockInfo.cs
- Test5_板砖工人类
- BlockWorker.cs
- Test6_输入模块
- InputThread.cs
- Program.cs
Test1_场景切换相关
BeginScene.cs
namespace CSharp俄罗斯方块 { internal class BeginScene : BegionOrEndScene { public BeginScene() { strTitle = "俄罗斯方块"; strOne = "开始游戏"; } public override void EnterJDoSomthing() { if (nowSelIndex == 0) { Game.ChangeScene(E_SceneType.Game); } else { Environment.Exit(0); } } } }
BegionOrEndScene.cs
namespace CSharp俄罗斯方块 { abstract internal class BegionOrEndScene : ISceneUpdate { protected int nowSelIndex = 0; protected string strTitle; protected string strOne; public abstract void EnterJDoSomthing(); public void Update() { 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 = 1; } break; case ConsoleKey.S: nowSelIndex++; if (nowSelIndex > 1) { nowSelIndex = 0; } break; case ConsoleKey.J: EnterJDoSomthing(); break; } } } }
EndScene.cs
namespace CSharp俄罗斯方块 { internal class EndScene : BegionOrEndScene { public EndScene() { strTitle = "结束游戏"; strOne = "回到开始界面"; } public override void EnterJDoSomthing() { if(nowSelIndex == 0) { Game.ChangeScene(E_SceneType.Begin); } else { Environment.Exit(0); } } } }
Game.cs
namespace CSharp俄罗斯方块 { enum E_SceneType { Begin, Game, End, } internal 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; } } } }
GameScene.cs
namespace CSharp俄罗斯方块 { internal class GameScene : ISceneUpdate { Map map; BlockWorker blockWorker; //bool isRunning; //新开线程 //Thread inputThread; public GameScene() { map = new Map(this); blockWorker = new BlockWorker(); InputThread.Instance.inputEvent += CheckInputThread; //isRunning = true; //inputThread = new Thread(CheckInputThread); 设置成后台线程(生命周期随主线程) //inputThread.IsBackground = true; 开启线程 //inputThread.Start(); } public void StopThread() { //isRunning = false; //inputThread = null; //移除输入事件监听 InputThread.Instance.inputEvent -= CheckInputThread; } 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.CanMoveR_L(E_Change_Type.Left, map)) blockWorker.MoveR_L(E_Change_Type.Left); break; case ConsoleKey.D: if (blockWorker.CanMoveR_L(E_Change_Type.Right, map)) blockWorker.MoveR_L(E_Change_Type.Right); break; case ConsoleKey.S: if (blockWorker.CanDown(map)) blockWorker.AutoMove(); break; } } } //} } public void Update() { lock (blockWorker) { map.Draw(); blockWorker.Draw(); if (blockWorker.CanDown(map)) blockWorker.AutoMove(); } //线程休眠减速 Thread.Sleep(100); } } }
ISceneUpdate.cs
namespace CSharp俄罗斯方块 { ///
/// 场景更新接口 /// internal interface ISceneUpdate { void Update(); } }Test2_绘制对象基类和枚举信息
DrawObject.cs
namespace CSharp俄罗斯方块 { ///
/// 绘制类型 /// enum E_DrawType { ////// 墙壁 /// Wall, ////// 正方形方块 /// Cube, ////// 直线 /// Line, ////// 坦克 /// Tank, ////// 左梯子 /// Left_Ladder, ////// 右梯子 /// Right_Ladder, ////// 左长梯子 /// Left_Long_ladder, ////// 右长梯子 /// Right_Long_ladder, } internal 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) { 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.Yellow; break; } Console.Write("■"); } //擦除 public void ClearDraw() { if (pos.y < 0) return; Console.SetCursorPosition(pos.x, pos.y); Console.Write(" "); } ////// 附着墙壁方法 /// /// public void ChangeType(E_DrawType type) { this.type = type; } } }IDraw.cs
namespace CSharp俄罗斯方块 { internal interface IDraw { void Draw(); } }
Position.cs
namespace CSharp俄罗斯方块 { internal 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 left, Position right) { if (left.x == right.x && left.y == right.y) { return true; } return false; } public static bool operator !=(Position left, Position right) { if (left.x == right.x && left.y == right.y) { return false; } return true; } public static Position operator +(Position left, Position right) { return new Position(left.x + right.x, left.y + right.y); } } }
Test3_地图相关
Map.cs
namespace CSharp俄罗斯方块 { internal class Map : IDraw { //固定墙壁 private List
walls = new List (); //动态墙壁 public List dynamicWalls = new List (); private GameScene nowGameScene; //为了外部能快速得到地图边界 //动态墙壁的宽容量,小方块横向个数 public int w; public int h; //记录每一行有多少个小方块的容器,索引就是行号 private int[] recordInfo; public Map(GameScene scene) { nowGameScene = scene; h = Game.h - 6; 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(); } } public void AddWalls(List 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) { nowGameScene.StopThread(); Game.ChangeScene(E_SceneType.End); return; } //进行添加动态墙壁行的计数 recordInfo[h - walls[i].pos.y - 1]++; } ClearDraw(); CheckClear(); Draw(); } /// /// 检测是否跨层 /// public void CheckClear() { //遍历时安全移除,添加待移除数组 ListdelList = new List (); //要选择记录行中有多少个方块的容器 //数组判断这一行是否满 //遍历数组,检测数组里面存的数是不是w-2 for (int i = 0; i < recordInfo.Length; i++) { //如果这行满了需要移除 if (recordInfo[i] == w) { //1、这一行的所有方块移除 for (int j = 0; j < dynamicWalls.Count; j++) { //通过动态方块的y计算它在哪一行 if (i == h - dynamicWalls[j].pos.y - 1) { //待移除添加到记录列表 delList.Add(dynamicWalls[j]); } //2、要这一行之上的所有方块下移 else if (h - dynamicWalls[j].pos.y - 1 > 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; } } } } } Test4_坐标信息类
BlockInfo.cs
namespace CSharp俄罗斯方块 { internal class BlockInfo { private List
list; public BlockInfo(E_DrawType type) { list = new List (); 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: list.Add([new Position(0, -1), new Position(0, 1), new Position(0, 2)]); list.Add([new Position(-4, 0), new Position(-2, 0), new Position(2, 0)]); list.Add([new Position(0, -2), new Position(0, -1), new Position(0, 1)]); list.Add([new Position(-2, 0), new Position(2, 0), new Position(4, 0)]); break; case E_DrawType.Tank: list.Add([new Position(-2, 0), new Position(2, 0), new Position(0, 1)]); list.Add([new Position(0, -1), new Position(-2, 0), new Position(0, 1)]); list.Add([new Position(0, -1), new Position(-2, 0), new Position(2, 0)]); list.Add([new Position(0,-1), new Position(2, 0), new Position(0, 1)]); break; case E_DrawType.Left_Ladder: list.Add([new Position(0, -1), new Position(2, 0), new Position(2, 1)]); list.Add([new Position(2, 0), new Position(-2, 1), new Position(0, 1)]); list.Add([new Position(-2, -1), new Position(-2, 0), new Position(0, 1)]); list.Add([new Position(0, -1), new Position(2, -1), new Position(-2, 0)]); break; case E_DrawType.Right_Ladder: list.Add([new Position(0, -1), new Position(-2, 0), new Position(-2, 1)]); list.Add([new Position(-2, -1), new Position(0, -1), new Position(2, 0)]); list.Add([new Position(2, -1), new Position(2, 0), new Position(0, 1)]); list.Add([new Position(-2, 0), new Position(0, 1), new Position(2, 1)]); break; case E_DrawType.Left_Long_ladder: list.Add([new Position(-2, -1), new Position(0, -1), new Position(0, 1)]); list.Add([new Position(2, 1), new Position(-2, 0), new Position(2, 0)]); list.Add([new Position(0, -1), new Position(0, 1), new Position(2, 1)]); list.Add([new Position(-2, 0), new Position(2, 0), new Position(-2, 1)]); break; case E_DrawType.Right_Long_ladder: list.Add([new Position(0, -1), new Position(2, -1), new Position(0, 1)]); list.Add([new Position(-2, 0), new Position(2, 1), new Position(2, 0)]); list.Add([new Position(0, -1), new Position(0, 1), new Position(-2, 1)]); list.Add([new Position(-2, 0), new Position(2, 0), new Position(-2, -1)]); break; default: break; } } 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]; } } public int Count { get => list.Count; } } } Test5_板砖工人类
BlockWorker.cs
namespace CSharp俄罗斯方块 { enum E_Change_Type { Left, Right, } internal class BlockWorker : IDraw { //方块们 private List
blocks; //用Dictionary方便查找 private Dictionary blockInfoDic; //随机创建的方块具体形态信息 private BlockInfo nowBlockInfo; //当前形态的索引 private int nowInfoIndex; public BlockWorker() { blockInfoDic = new Dictionary () { { 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)}, }; RandomCreatBlock(); } public void Draw() { for (int i = 0; i < blocks.Count; i++) { blocks[i].Draw(); } } /// /// 随机创建方块 /// public void RandomCreatBlock() { Random r = new Random(); E_DrawType type = (E_DrawType)r.Next(1, 8); blocks = new List() { new DrawObject(type), new DrawObject(type), new DrawObject(type), new DrawObject(type), }; //定义0,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++) { //通过原点坐标信息绘制四个方块 blocks[i + 1].pos = pos[i] + blocks[0].pos; } } //擦除方法 public void ClearDraw() { for (int i = 0; i < blocks.Count; i++) { blocks[i].ClearDraw(); } } /// /// 方块变形 /// /// 左,右 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++) { blocks[i + 1].pos = pos[i] + blocks[0].pos; } //擦除之后绘制 Draw(); } ////// 判断能否变形 /// /// 地图方向 /// 地图墙壁 ///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; } /// /// 方块左右移动 /// /// 左,右 public void MoveR_L(E_Change_Type type) { //移动之前擦除 ClearDraw(); //根据传入的类型,决定左右移动,得到偏移位置 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(); } ////// 判断能否移动 /// /// 左,右移动 ///public bool CanMoveR_L(E_Change_Type type, Map map) { Position movePos = new Position(type == E_Change_Type.Left ? -2 : 2, 0); //左右边界重合,预判断pos 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; } //方块自动下落 public void AutoMove() { ClearDraw(); Position downMove = new Position(0, 1); for (int i = 0; i < blocks.Count; i++) { blocks[i].pos += downMove; } Draw(); } public bool CanDown(Map map) { Position downPos = new Position(0, 1); //预下落位置 Position pos; //边界 for (int i = 0; i < blocks.Count; i++) { pos = blocks[i].pos + downPos; if (pos.y >= map.h) { //碰到地图,此时变成地图的一部分 map.AddWalls(blocks); //创建新的随机方块 RandomCreatBlock(); return false; } } //动态方块 for (int i = 0; i < blocks.Count; i++) { pos = blocks[i].pos + downPos; for (int j = 0; j < map.dynamicWalls.Count; j++) { if (pos == map.dynamicWalls[j].pos) { //碰到方块,此时变成地图的一部分 map.AddWalls(blocks); RandomCreatBlock(); return false; } } } return true; } } } Test6_输入模块
InputThread.cs
namespace CSharp俄罗斯方块 { internal 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(); } } } }
Program.cs
using CSharp俄罗斯方块; Game game = new Game(); game.start();
还没有评论,来说两句吧...