这篇文章主要介绍了C# 实现俄罗斯方块的实例,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
概述
俄罗斯方块(Tetris)是一款由俄罗斯人阿列克谢·帕基特诺夫发明的休闲游戏,帕基特诺夫爱玩拼图,从拼图游戏里得到灵感,设计出了俄罗斯方块。由于上手简单、老少皆宜,从而家喻户晓,风靡世界。本文简述如何通过C#来实现俄罗斯方块,仅供学习分享使用,如有不足之处,还请指正。
涉及知识点
BackgroundWorker 在单独的线程上执行操作(主要执行比较耗时的操作)。
Action .NetFramework自带的一个委托方法。
TableLayoutPanel 表示一个面板,它可以在一个由行和列组成的网格中对其内容进行动态布局,本文主要用作俄罗斯方块的容器。
方块流程图
如下图所示,描述了俄罗斯方块的设计流程图
俄罗斯方块效果图
如下图所示:主要包括状态,得分,开始按钮,停止按钮,按键盘左右箭头移动等功能
核心代码
1. 定义方块的形状
如下所示:共7中形状
/// <summary>
/// 俄罗斯方块的形状
/// </summary>
public enum TetrisStyle
{
S = 0,
Z = 1,
L = 2,
J = 3,
I = 4,
O = 5,
T = 6
}
2. 定义移动的方向
如下所示:默认向下移动,同时可以左右移动
/// <summary>
/// 俄罗斯方块移动方向
/// </summary>
public enum TetrisDirection
{
UP = 0,//上,表示顺时针旋转
DOWN = 1,//下,表示向下移动
LEFT = 2,//左,表示往左移动
RIGHT = 3, //表示向右移动
DEFAULT=4 //默认动作
}
3. 俄罗斯方块元素
如下所示,每一种形状都由四个方块组成,根据不同形状设置不同的位置
/// <summary>
/// 俄罗斯方块元素
/// </summary>
public class TetrisElement
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="style"></param>
public TetrisElement(TetrisStyle style) {
this.style = style;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="style">形状</param>
/// <param name="content">内容</param>
/// <param name="location">位置</param>
public TetrisElement(TetrisStyle style, Point[] content, Point location)
{
this.style = style;
this.content = content;
this.location = location;
}
/// <summary>
/// 元素字母类型
/// </summary>
public TetrisStyle style { get; set; }
/// <summary>
/// 内容
/// </summary>
public Point[] content { get; set; }
/// <summary>
/// 元素位置
/// </summary>
public Point location { get; set; }
/// <summary>
/// 位置改变
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public void move(int x, int y)
{
this.location = new Point(x, y);
}
public Point[] getContent(TetrisStyle style)
{
//内容由四个点组成,顺序:先上后下,先左后右
Point[] content = new Point[4];
switch (style)
{
case TetrisStyle.I:
//I形状
content[0] = new Point(0, 0);
content[1] = new Point(0, 1);
content[2] = new Point(0, 2);
content[3] = new Point(0, 3);
break;
case TetrisStyle.J:
//J形状
content[0] = new Point(1, 0);
content[1] = new Point(1, 1);
content[2] = new Point(1, 2);
content[3] = new Point(0, 2);
break;
case TetrisStyle.L:
//L形状
content[0] = new Point(0, 0);
content[1] = new Point(0, 1);
content[2] = new Point(0, 2);
content[3] = new Point(1, 2);
break;
case TetrisStyle.O:
//O形状
content[0] = new Point(0, 0);
content[1] = new Point(1, 0);
content[2] = new Point(0, 1);
content[3] = new Point(1, 1);
break;
case TetrisStyle.S:
//S形状
content[0] = new Point(2, 0);
content[1] = new Point(1, 0);
content[2] = new Point(1, 1);
content[3] = new Point(0, 1);
break;
case TetrisStyle.T:
//T形状
content[0] = new Point(0, 0);
content[1] = new Point(1, 0);
content[2] = new Point(2, 0);
content[3] = new Point(1, 1);
break;
case TetrisStyle.Z:
//Z形状
content[0] = new Point(0, 0);
content[1] = new Point(1, 0);
content[2] = new Point(1, 1);
content[3] = new Point(2, 1);
break;
default:
//默认I
content[0] = new Point(0, 0);
content[1] = new Point(0, 1);
content[2] = new Point(0, 2);
content[3] = new Point(0, 3);
break;
}
return content;
}
}
4. 容器类
如下所示:容器类主要是移动方块元素,并更新页面上的值
/// <summary>
/// 俄罗斯方块容器
/// </summary>
public class TetrisContainer
{
private int[,] tetris = new int[10, 20];//定义二维数组,表示坐标信息,默认值为0
public Action<Point,Point[],TetrisDirection> onPartialChanged;//局部变更事件
public Action<int[,]> onFullChanged;//元素全变更事件,即有整行被清除事件
public Action onCompleted; //结束事件
public int scorce = 0;
/// <summary>
/// 状态发生改变
/// </summary>
/// <param name="element"></param>
/// <param name="direction"></param>
/// <returns></returns>
public TetrisElement change(TetrisElement element, TetrisDirection direction)
{
TetrisElement tmp=null;
//判断不同的方向
switch (direction) {
case TetrisDirection.DEFAULT:
//如果可以向下移动
if (checkDefault(element))
{
//向下移动一个元素
element.move(element.location.X, element.location.Y + 1);
tmp = element;
}
else {
//如果不可以向下移动,则更新容器
updateTetris(element);
tmp = null;
}
break;
case TetrisDirection.DOWN:
break;
case TetrisDirection.UP:
break;
case TetrisDirection.LEFT:
if (checkLeft(element)){
//判断是否可以向左移动
//向下移动一个元素
element.move(element.location.X-1, element.location.Y);
tmp = element;
}
break;
case TetrisDirection.RIGHT:
if (checkRight(element))
{
//判断是否可以右左移动
//向下移动一个元素
element.move(element.location.X+1, element.location.Y);
tmp = element;
}
break;
}
//局部变更
if (onPartialChanged != null)
{
Point location = element.location;
Point[] content = new Point[4];
element.content.CopyTo(content, 0);
for (int i = 0; i < content.Length; i++)
{
content[i].X = location.X + content[i].X;
content[i].Y = location.Y + content[i].Y;
}
onPartialChanged(location,content,direction);
}
//判断游戏是否结束
if (onCompleted != null) {
if (checkComplete()) {
onCompleted();
}
}
//全部变更
if (onFullChanged != null)
{
//判断是是否有权为1的行,如果有则消掉
int[] rows = checkAllTetris();
if (rows.Length>0)
{
updateAllTetris(rows);//消掉行
onFullChanged(tetris);
}
}
return tmp;
}
/// <summary>
/// 更新tetris
/// </summary>
/// <param name="element"></param>
private void updateTetris(TetrisElement element)
{
Point location = element.location;
Point[] content = element.content;
int minX = element.getMinX(element.style);
int maxX = element.getMaxX(element.style);
int minY = element.getMinY(element.style);
int maxY = element.getMaxY(element.style);
foreach (Point p in content)
{
if (location.Y + p.Y < 20 && location.Y + p.Y >= 0 && location.X + p.X >= 0 && location.X + p.X < 10)
{
this.tetris[location.X + p.X, location.Y + p.Y] = 1;
}
}
}
/// <summary>
/// 检查全部列
/// </summary>
private int[] checkAllTetris()
{
List<int> lst = new List<int>();
//20行
for (int y = 0; y < 20; y++)
{
int col = 0;
//10列
for (int x = 0; x < 10; x++)
{
if (tetris[x, y] == 0)
{
break;
}
else
{
col += 1;
}
}
if (col == 10)
{
col = 0;
lst.Add(y);
}
}
return lst.ToArray();
}
/// <summary>
/// 更新
/// </summary>
private void updateAllTetris(int[] rows) {
foreach (int row in rows) {
//当前行清掉
for (int x = 0; x < 10; x++) {
tetris[x, row] = 0;
}
//row行之上的往下移动一行
for (int y = row-1; y >=0; y--) {
for (int x = 0; x < 10; x++) {
if (tetris[x, y] == 1) {
tetris[x, y + 1] = 1;
tetris[x, y] = 0;
}
}
}
}
}
/// <summary>
/// 判断游戏是否结束
/// </summary>
/// <returns></returns>
private bool checkComplete() {
bool isComplete = false;
for (int i = 0; i < 10; i++) {
if (tetris[i, 0] == 1) {
isComplete = true;
break;
}
}
return isComplete;
}
/// <summary>
/// 更新得分
/// </summary>
/// <param name="s"></param>
public void updateScore(int s) {
this.scorce = this.scorce + s;
}
/// <summary>
/// 重置信息
/// </summary>
public void Reset() {
this.tetris = new int[10, 20];
this.scorce = 0;
}
}
5. 随机生成方块元素和起始位置
/// <summary>
/// 静态函数,生成Tetris元素对象
/// </summary>
/// <returns></returns>
public static TetrisElement generate()
{
Random r = new Random(0);
//随机生成形状
int tstyle = getRandom();
tstyle = tstyle % 7;
TetrisStyle style = TetrisStyle.I;
style = (TetrisStyle)Enum.Parse(typeof(TetrisStyle), tstyle.ToString());
//随机生成起始坐标
int x = getRandom();
x = x % 10;
int y = 0;
//根据形状生成位置信息
TetrisElement element = new TetrisElement(style);
//内容由四个点组成,顺序:先上后下,先左后右
Point[] content = element.getContent(style);
//获取最小坐标和最大坐标,防止越界
int minX = element.getMinX(style);
int minY = element.getMinY(style);
int maxX = element.getMaxX(style);
int maxY = element.getMaxY(style);
//修正起始坐标
x = (x <= minX) ? minX : x;
x = (x >= maxX) ? maxX : x;
y = minY;
Point location = new Point(x, y);
element.location = location;
element.content = content;
return element;
}
备注
源码下载链接
以上就是C# 实现俄罗斯方块(附源码)的详细内容,更多关于C# 实现俄罗斯方块的资料请关注得得之家其它相关文章!
本文标题为:C# 实现俄罗斯方块(附源码)
基础教程推荐
- C# windows语音识别与朗读实例 2023-04-27
- C#控制台实现飞行棋小游戏 2023-04-22
- C# 调用WebService的方法 2023-03-09
- ZooKeeper的安装及部署教程 2023-01-22
- 一个读写csv文件的C#类 2022-11-06
- linux – 如何在Debian Jessie中安装dotnet core sdk 2023-09-26
- C#类和结构详解 2023-05-30
- C# List实现行转列的通用方案 2022-11-02
- winform把Office转成PDF文件 2023-06-14
- unity实现动态排行榜 2023-04-27