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#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
- 这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
- 这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
- 这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
- 本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
- 本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)
这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25- 这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
- 这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
- php语言实现redis的客户端与服务端有一些区别了因为前面介绍过服务端了这里我们来介绍客户端吧,希望文章对各位有帮助。 为了更好的了解redis协议,我们用php来实现...2016-11-25
- 最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
- 本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
- 轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
- 有时我们在页面上需要选择数值范围,如购物时选取价格区间,购买主机时自主选取CPU,内存大小配置等,使用直观的滑块条直接选取想要的数值大小即可,无需手动输入数值,操作简单又方便。HTML首先载入jQuery库文件以及jRange相关...2015-03-15
- 这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
- 这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
- 这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25