开发环境:window10
IDE:Visual Studio 2019
Language:C#
类型:控制台
注:不具备可玩性,UI需要换种呈现方式,晃得眼花,千万别玩-头大
using ConsoleApp.Tetris;
using System;
namespace Tetris
{
class Program
{
static void Main(string[] args)
{
Control control = new Control();
control.Start();
Console.ReadKey();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Tetris
{
public enum State
{
NotStarted = 0,
Starting = 1,
Pause = 2,
GameOver = 10
}
public class Control
{
public static string Key_Left = "4";//左移
public static string Key_Right = "6";//右移
public static string Key_Rotate = "8";//旋转
public static string Key_Down = "2";//向下
public static string Key_Pause = "0";//暂停
private Graph graphArea;
private GraphFactory factory;
private Graph currentMoveArea = null;
private Graph lastValidArea = null;
private int DefaulTurnTime = 200;
private int CurrentTurnTime = 200;
private string key = "";
private Graph validArea = null;
private State state;
public Control()
{
graphArea = new Graph(12, 20);
factory = new GraphFactory(graphArea);
}
public void Start()
{
state = State.Starting;
//刷新画板区域
RefreshGraphArea();
while (true)
{
//监听按键
MonitorKey();
//处理画板移动区域
HandleGraphMoveArea();
//检测结束
if (state == State.GameOver)
break;
//处理画板 结算或移动继续移动
HandleGraphArea();
Task.Delay(CurrentTurnTime).Wait();
}
}
///
/// 定时绘制画板
///
private void RefreshGraphArea()
{
Task.Run(() => {
while (true)
{
if (state == State.Starting)
{
if (validArea != null)
validArea.Draw();
else
graphArea.Draw();
}
Task.Delay(CurrentTurnTime).Wait();
if (graphArea == null)
break;
}
});
}
///
/// 监听按键
///
private void MonitorKey()
{
while (Console.KeyAvailable)
{
var input = Console.ReadKey(true);
key = input.KeyChar.ToString();
}
}
///
/// 处理移动区域
///
private void HandleGraphMoveArea()
{
//如果移动区域不存在就创建一个信息
if (currentMoveArea == null)
{
CreateMoveArea();
}
//如果移动区域存在则移动
else
{
MoveArea();
}
}
///
/// 创建新的移动区域
///
private void CreateMoveArea()
{
currentMoveArea = factory.CreateArea();
validArea = graphArea.DrawOtherGraph(currentMoveArea);
//如果创建出来的图形 在画板中无法绘画 则结束
if (validArea == null)
{
Console.WriteLine("game over");
state = State.GameOver;
}
}
///
/// 移动处理
///
private void MoveArea()
{
if (key == Key_Pause)
{
Pause();
}
if (state != State.Pause)
{
if (currentMoveArea != null)
{
currentMoveArea.RowOffset += 1;
}
if (key == Key_Left)
{
MoveLeft();
}
else if (key == Key_Right)
{
MoveRight();
}
else if (key == Key_Rotate)
{
Rotate();
}
else if (key == Key_Down)
{
ChangeMoveSpeed();
}
validArea = graphArea.DrawOtherGraph(currentMoveArea);
}
}
///
/// 暂停
///
private void Pause()
{
if (state != State.GameOver)
state = state == State.Pause ? State.Starting : State.Pause;
key = "";
}
///
/// 改变移动(下降)速度
///
private void ChangeMoveSpeed()
{
CurrentTurnTime = CurrentTurnTime / 2;
key = "";
}
///
/// 每轮移动后 统计画板
///
private void HandleGraphArea()
{
if (validArea != null)
{
//移动区域移动后整个区域有效则记录有效区域,作为碰撞后结算依据
lastValidArea = validArea;
}
else
{
Settlement();
}
}
///
/// 碰撞 结算
///
private void Settlement()
{
graphArea = lastValidArea;
currentMoveArea = null;
if (graphArea.RemoveRowAllColor())
graphArea.Draw();
CurrentTurnTime = DefaulTurnTime;
}
private void Rotate()
{
var temp = currentMoveArea.DeepClone();
currentMoveArea = currentMoveArea.Rotate();
if (currentMoveArea == null)
currentMoveArea = temp;
else
{
var moveArea = graphArea.DrawOtherGraph(currentMoveArea);
if (moveArea == null)
currentMoveArea = temp;
}
key = "";
}
private void MoveRight()
{
currentMoveArea.ColumnOffset++;
if (currentMoveArea.ColumnOffset + currentMoveArea.ColumnNumber >= graphArea.ColumnNumber)
currentMoveArea.ColumnOffset = graphArea.ColumnNumber - currentMoveArea.ColumnNumber;
var moveArea = graphArea.DrawOtherGraph(currentMoveArea);
if (moveArea == null)
currentMoveArea.ColumnOffset--;
key = "";
}
private void MoveLeft()
{
currentMoveArea.ColumnOffset--;
if (currentMoveArea.ColumnOffset < 0)
currentMoveArea.ColumnOffset = 0;
var moveArea = graphArea.DrawOtherGraph(currentMoveArea);
if (moveArea == null)
currentMoveArea.ColumnOffset++;
key = "";
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
namespace ConsoleApp.Tetris
{
public class GraphFactory
{
public Graph[] GraphProducts { get; set; }
public Graph MainArea { get; set; }
public GraphFactory(Graph area)
{
MainArea = area;
GraphProducts = new Graph[]
{
new Line() { ColumnOffset = area.ColumnNumber / 2 },
new Instability(){ ColumnOffset = area.ColumnNumber / 2 },
new Sharp(){ ColumnOffset = area.ColumnNumber / 2 },
new Square () { ColumnOffset = area.ColumnNumber / 2 }
};
}
public Graph CreateArea()
{
byte[] buffer = Guid.NewGuid().ToByteArray();
int iRoot = BitConverter.ToInt32(buffer, 0);
Random random = new Random(iRoot);
int index = random.Next(0, GraphProducts.Length);
return GraphProducts[index].DeepClone();
}
}
///
/// 口
/// 口
/// 口
/// 口
///
[Serializable]
public class Line : Graph
{
public const int ROW = 4;
public const int COLUMN = 1;
public Line() : base(COLUMN, ROW)
{
foreach (var row in Rows)
{
foreach (var element in row.Elements)
{
element.IsColor = true;
element.Color = ConsoleColor.Yellow;
}
}
}
}
///
/// 口
/// 口口
/// 口
///
[Serializable]
public class Instability : Graph
{
public const int ROW = 3;
public const int COLUMN = 2;
public Instability() : base(COLUMN, ROW)
{
foreach (var row in Rows)
{
var rowIndex = Rows.IndexOf(row);
foreach (var element in row.Elements)
{
var columnIndex = row.Elements.IndexOf(element);
if (rowIndex == 0)
{
if (columnIndex == 1)
element.IsColor = true;
}
else if (rowIndex == 1)
{
element.IsColor = true;
}
else
{
if (columnIndex == 0)
element.IsColor = true;
}
element.Color = ConsoleColor.Green;
}
}
}
}
///
/// 口
/// 口口口
///
[Serializable]
public class Sharp : Graph
{
public const int ROW = 2;
public const int COLUMN = 3;
public Sharp() : base(COLUMN, ROW)
{
foreach (var row in Rows)
{
var rowIndex = Rows.IndexOf(row);
foreach (var element in row.Elements)
{
var columnIndex = row.Elements.IndexOf(element);
if (rowIndex == 0 && columnIndex == COLUMN / 2)
{
element.IsColor = true;
}
else if (rowIndex == 1)
{
element.IsColor = true;
}
element.Color = ConsoleColor.Red;
}
}
}
}
///
/// 田
///
[Serializable]
public class Square : Graph
{
public const int ROW = 2;
public const int COLUMN = 2;
public Square() : base(COLUMN, ROW)
{
foreach (var row in Rows)
{
foreach (var element in row.Elements)
{
element.IsColor = true;
element.Color = ConsoleColor.White;
}
}
}
}
[Serializable]
public class Graph
{
public const string GRAGH_DISPAY = "口";
public int ColumnOffset { get; set; }
public int RowOffset { get; set; }
public int ColumnNumber { get; set; }
public int RowNumber { get; set; }
public List<RowElement> Rows { get; set; }
//移除行的数量
public int RemoveRow { get; set; } = 0;
public Graph(int columnNumber, int rowNumber)
{
ColumnOffset = 0;
RowOffset = 0;
ColumnNumber = columnNumber;
RowNumber = rowNumber;
Init();
}
public void Draw()
{
Console.Clear();
for (int column = 0; column <= ColumnNumber; column++)
Console.Write("--");
Console.WriteLine();
for (int row = 0; row < RowNumber; row++)
{
Console.Write("|");
var rowElement = Rows[row];
for (int column = 0; column < ColumnNumber; column++)
{
var element = rowElement.Elements[column];
if (element.IsColor)
{
Console.ForegroundColor = element.Color;
Console.Write(GRAGH_DISPAY);
Console.ResetColor();
}
else
Console.Write(" ");
}
Console.Write("|");
Console.WriteLine();
}
for (int column = 0; column <= ColumnNumber; column++)
Console.Write("--");
Console.WriteLine($"得分:{RemoveRow}");
}
private void Init()
{
Rows = new List<RowElement>();
for (int row = 0; row < RowNumber; row++)
{
RowElement rowElement = CreateRow();
Rows.Add(rowElement);
}
}
private RowElement CreateRow()
{
var rowElement = new RowElement(ColumnNumber);
for (int column = 0; column < ColumnNumber; column++)
{
rowElement.Elements.Add(new Element());
}
return rowElement;
}
///
/// 将一个图形 画到当前图形上
///
///
/// 新的图形,如果有色块重叠则null
public Graph DrawOtherGraph(Graph otherGraph)
{
Graph offsetArea = this.DeepClone();
for (int row = 0; row < otherGraph.RowNumber; row++)
{
if (otherGraph.RowOffset < 0 || otherGraph.RowOffset + row >= RowNumber)
return null;
var offsetRow = offsetArea.Rows[otherGraph.RowOffset + row];
var areaRow = otherGraph.Rows[row];
for (int column = 0; column < otherGraph.ColumnNumber; column++)
{
if (otherGraph.ColumnOffset < 0 || otherGraph.ColumnOffset + column >= ColumnNumber)
return null;
var offsetColumnElement = offsetRow.Elements[otherGraph.ColumnOffset + column];
var areaRowColumnElement = areaRow.Elements[column];
if (offsetColumnElement.IsColor && areaRowColumnElement.IsColor)
{
return null;
}
else
{
if (areaRowColumnElement.IsColor)
{
offsetColumnElement.IsColor = areaRowColumnElement.IsColor;
offsetColumnElement.Color = areaRowColumnElement.Color;
}
}
}
}
return offsetArea;
}
///
/// 旋转
///
///
///
public virtual Graph Rotate(bool isRight = true)
{
//重新初始化一个图形
Graph graph = new Graph(this.RowNumber, this.ColumnNumber);
graph.ColumnOffset = ColumnOffset;
graph.RowOffset = RowOffset;
for (int i = 0; i < Rows.Count; i++)
{
var row = Rows[i];
for (int j = 0; j < row.Elements.Count; j++)
{
var element = row.Elements[j];
var graphElement = graph.Rows[j].Elements[i];
if (isRight)
graphElement = graph.Rows[j].Elements[graph.ColumnNumber - i - 1];
graphElement.IsColor = element.IsColor;
graphElement.Color = element.Color;
}
}
return graph;
}
///
/// 移除全为颜色的行
///
///
public bool RemoveRowAllColor()
{
List<int> removeIndex = new List<int>();
for (int row = RowNumber - 1; row >= 0; row--)
{
var rowElement = Rows[row];
if (!rowElement.Elements.ToList().Any(column => column.IsColor == false))
{
RemoveRow++;
rowElement.IsAllColor = true;
removeIndex.Add(row);
}
}
Graph area = new Graph(ColumnNumber, RowNumber);
int rowIndex = RowNumber - 1;
for (int row = RowNumber - 1; row > 0; row--)
{
var rowElement = Rows[row];
if (!rowElement.IsAllColor)
{
area.Rows[rowIndex--] = rowElement;
}
if (row == 1 && rowIndex < RowNumber - 1)
{
area.Rows[0] = CreateRow();
}
}
Rows = area.Rows;
return rowIndex < RowNumber - 1;
}
public Graph DeepClone()
{
using (Stream stream = new MemoryStream())
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
return binaryFormatter.Deserialize(stream) as Graph;
}
}
}
[Serializable]
public class RowElement
{
public int ColumnNumber { get; set; }
public List<Element> Elements { get; set; }
public bool IsAllColor { get; set; } = false;
public RowElement(int rowNumber)
{
ColumnNumber = rowNumber;
Elements = new List<Element>();
}
}
[Serializable]
public class Element
{
public bool IsColor { get; set; }
public ConsoleColor Color { get; set; }
}
}