概述

俄罗斯方块(Tetris)是一款由俄罗斯人阿列克谢·帕基特诺夫发明的休闲游戏,帕基特诺夫爱玩拼图,从拼图游戏里得到灵感,设计出了俄罗斯方块。由于上手简单、老少皆宜,从而家喻户晓,风靡世界。本文简述如何通过C#来实现俄罗斯方块,仅供学习分享使用,如有不足之处,还请指正。

涉及知识点

  1. BackgroundWorker 在单独的线程上执行操作(主要执行比较耗时的操作)。
  2. Action .NetFramework自带的一个委托方法。
  3. TableLayoutPanel  表示一个面板,它可以在一个由行和列组成的网格中对其内容进行动态布局,本文主要用作俄罗斯方块的容器。

方块流程图

如下图所示,描述了俄罗斯方块的设计流程图

俄罗斯方块效果图

如下图所示:主要包括状态,得分,开始按钮,停止按钮,按键盘左右箭头移动等功能

核心代码

1. 定义方块的形状

如下所示:共7中形状

 1 /// <summary>
 2     /// 俄罗斯方块的形状
 3     /// </summary>
 4     public enum TetrisStyle
 5     {
 6         S = 0,
 7         Z = 1,
 8         L = 2,
 9         J = 3,
10         I = 4,
11         O = 5,
12         T = 6
13     }

2. 定义移动的方向

如下所示:默认向下移动,同时可以左右移动

 1 /// <summary>
 2     /// 俄罗斯方块移动方向
 3     /// </summary>
 4     public enum TetrisDirection
 5     {
 6         UP = 0,//上,表示顺时针旋转
 7         DOWN = 1,//下,表示向下移动
 8         LEFT = 2,//左,表示往左移动
 9         RIGHT = 3, //表示向右移动
10         DEFAULT=4 //默认动作
11     }

3. 俄罗斯方块元素

如下所示,每一种形状都由四个方块组成,根据不同形状设置不同的位置

  1 /// <summary>
  2     /// 俄罗斯方块元素
  3     /// </summary>
  4     public class TetrisElement
  5     {
  6         /// <summary>
  7         /// 构造函数
  8         /// </summary>
  9         /// <param name="style"></param>
 10         public TetrisElement(TetrisStyle style) {
 11             this.style = style;
 12         }
 13
 14         /// <summary>
 15         /// 构造函数
 16         /// </summary>
 17         /// <param name="style">形状</param>
 18         /// <param name="content">内容</param>
 19         /// <param name="location">位置</param>
 20         public TetrisElement(TetrisStyle style, Point[] content, Point location)
 21         {
 22             this.style = style;
 23             this.content = content;
 24             this.location = location;
 25         }
 26
 27         /// <summary>
 28         /// 元素字母类型
 29         /// </summary>
 30         public TetrisStyle style { get; set; }
 31
 32         /// <summary>
 33         /// 内容
 34         /// </summary>
 35         public Point[] content { get; set; }
 36
 37         /// <summary>
 38         /// 元素位置
 39         /// </summary>
 40         public Point location { get; set; }
 41
 44         /// <summary>
 45         /// 位置改变
 46         /// </summary>
 47         /// <param name="x"></param>
 48         /// <param name="y"></param>
 49         public void move(int x, int y)
 50         {
 51             this.location = new Point(x, y);
 52         }
 53
 54         public Point[] getContent(TetrisStyle style)
 55         {
 56             //内容由四个点组成,顺序:先上后下,先左后右
 57             Point[] content = new Point[4];
 58             switch (style)
 59             {
 60                 case TetrisStyle.I:
 61                     //I形状
 62                     content[0] = new Point(0, 0);
 63                     content[1] = new Point(0, 1);
 64                     content[2] = new Point(0, 2);
 65                     content[3] = new Point(0, 3);
 66                     break;
 67                 case TetrisStyle.J:
 68                     //J形状
 69                     content[0] = new Point(1, 0);
 70                     content[1] = new Point(1, 1);
 71                     content[2] = new Point(1, 2);
 72                     content[3] = new Point(0, 2);
 73                     break;
 74                 case TetrisStyle.L:
 75                     //L形状
 76                     content[0] = new Point(0, 0);
 77                     content[1] = new Point(0, 1);
 78                     content[2] = new Point(0, 2);
 79                     content[3] = new Point(1, 2);
 80                     break;
 81                 case TetrisStyle.O:
 82                     //O形状
 83                     content[0] = new Point(0, 0);
 84                     content[1] = new Point(1, 0);
 85                     content[2] = new Point(0, 1);
 86                     content[3] = new Point(1, 1);
 87                     break;
 88                 case TetrisStyle.S:
 89                     //S形状
 90                     content[0] = new Point(2, 0);
 91                     content[1] = new Point(1, 0);
 92                     content[2] = new Point(1, 1);
 93                     content[3] = new Point(0, 1);
 94                     break;
 95                 case TetrisStyle.T:
 96                     //T形状
 97                     content[0] = new Point(0, 0);
 98                     content[1] = new Point(1, 0);
 99                     content[2] = new Point(2, 0);
100                     content[3] = new Point(1, 1);
101                     break;
102                 case TetrisStyle.Z:
103                     //Z形状
104                     content[0] = new Point(0, 0);
105                     content[1] = new Point(1, 0);
106                     content[2] = new Point(1, 1);
107                     content[3] = new Point(2, 1);
108                     break;
109                 default:
110                     //默认I
111                     content[0] = new Point(0, 0);
112                     content[1] = new Point(0, 1);
113                     content[2] = new Point(0, 2);
114                     content[3] = new Point(0, 3);
115                     break;
116             }
117             return content;
118         }
119     }

4. 容器类

如下所示:容器类主要是移动方块元素,并更新页面上的值

  1 /// <summary>
  2     /// 俄罗斯方块容器
  3     /// </summary>
  4     public class TetrisContainer
  5     {
  6         private int[,] tetris = new int[10, 20];//定义二维数组,表示坐标信息,默认值为0
  7
  8         public Action<Point,Point[],TetrisDirection> onPartialChanged;//局部变更事件
  9
 10         public Action<int[,]> onFullChanged;//元素全变更事件,即有整行被清除事件
 11
 12         public Action onCompleted; //结束事件
 13
 14         public int scorce = 0;
 15
 16         /// <summary>
 17         /// 状态发生改变
 18         /// </summary>
 19         /// <param name="element"></param>
 20         /// <param name="direction"></param>
 21         /// <returns></returns>
 22         public TetrisElement change(TetrisElement element, TetrisDirection direction)
 23         {
 24             TetrisElement tmp=null;
 25             //判断不同的方向
 26             switch (direction) {
 27                 case TetrisDirection.DEFAULT:
 28                     //如果可以向下移动
 29                     if (checkDefault(element))
 30                     {
 31                         //向下移动一个元素
 32                         element.move(element.location.X, element.location.Y + 1);
 33                         tmp = element;
 34                     }
 35                     else {
 36                         //如果不可以向下移动,则更新容器
 37                         updateTetris(element);
 38                         tmp = null;
 39                     }
 40
 41                     break;
 42                 case TetrisDirection.DOWN:
 43                     break;
 44                 case TetrisDirection.UP:
 45                     break;
 46                 case TetrisDirection.LEFT:
 47                     if (checkLeft(element)){
 48                         //判断是否可以向左移动
 49                         //向下移动一个元素
 50                         element.move(element.location.X-1, element.location.Y);
 51                         tmp = element;
 52                     }
 53                     break;
 54                 case TetrisDirection.RIGHT:
 55                     if (checkRight(element))
 56                     {
 57                         //判断是否可以右左移动
 58                         //向下移动一个元素
 59                         element.move(element.location.X+1, element.location.Y);
 60                         tmp = element;
 61                     }
 62                     break;
 63             }
 64
 65             //局部变更
 66             if (onPartialChanged != null)
 67             {
 68                 Point location = element.location;
 69                 Point[] content = new Point[4];
 70                 element.content.CopyTo(content, 0);
 71
 72                 for (int i = 0; i < content.Length; i++)
 73                 {
 74                     content[i].X = location.X + content[i].X;
 75                     content[i].Y = location.Y + content[i].Y;
 76                 }
 77                 onPartialChanged(location,content,direction);
 78             }
 79
 80             //判断游戏是否结束
 81             if (onCompleted != null) {
 82                 if (checkComplete()) {
 83                     onCompleted();
 84                 }
 85             }
 86
 87             //全部变更
 88             if (onFullChanged != null)
 89             {
 90                 //判断是是否有权为1的行,如果有则消掉
 91                 int[] rows = checkAllTetris();
 92                 if (rows.Length>0)
 93                 {
 94                     updateAllTetris(rows);//消掉行
 95                     onFullChanged(tetris);
 96                 }
 97             }
 98
 99             return tmp;
100         }
101
102         /// <summary>
103         /// 更新tetris
104         /// </summary>
105         /// <param name="element"></param>
106         private void updateTetris(TetrisElement element)
107         {
108             Point location = element.location;
109             Point[] content = element.content;
110             int minX = element.getMinX(element.style);
111             int maxX = element.getMaxX(element.style);
112             int minY = element.getMinY(element.style);
113             int maxY = element.getMaxY(element.style);
114             foreach (Point p in content)
115             {
116                 if (location.Y + p.Y < 20 && location.Y + p.Y >= 0 && location.X + p.X >= 0 && location.X + p.X < 10)
117                 {
118                     this.tetris[location.X + p.X, location.Y + p.Y] = 1;
119                 }
120             }
121         }
122
123         /// <summary>
124         /// 检查全部列
125         /// </summary>
126         private int[] checkAllTetris()
127         {
128             List<int> lst = new List<int>();
129             //20行
130             for (int y = 0; y < 20; y++)
131             {
132                 int col = 0;
133                 //10列
134                 for (int x = 0; x < 10; x++)
135                 {
136                     if (tetris[x, y] == 0)
137                     {
138                         break;
139                     }
140                     else
141                     {
142                         col += 1;
143                     }
144                 }
145                 if (col == 10)
146                 {
147                     col = 0;
148                     lst.Add(y);
149                 }
150             }
151             return lst.ToArray();
152         }
153
154         /// <summary>
155         /// 更新
156         /// </summary>
157         private void updateAllTetris(int[] rows) {
158             foreach (int row in rows) {
159                 //当前行清掉
160                 for (int x = 0; x < 10; x++) {
161                     tetris[x, row] = 0;
162                 }
163                 //row行之上的往下移动一行
164                 for (int y = row-1; y >=0; y--) {
165                     for (int x = 0; x < 10; x++) {
166                         if (tetris[x, y] == 1) {
167                             tetris[x, y + 1] = 1;
168                             tetris[x, y] = 0;
169                         }
170                     }
171                 }
172             }
173         }
174
175         /// <summary>
176         /// 判断游戏是否结束
177         /// </summary>
178         /// <returns></returns>
179         private bool checkComplete() {
180             bool isComplete = false;
181             for (int i = 0; i < 10; i++) {
182                 if (tetris[i, 0] == 1) {
183                     isComplete = true;
184                     break;
185                 }
186             }
187             return isComplete;
188         }
189
190         /// <summary>
191         /// 更新得分
192         /// </summary>
193         /// <param name="s"></param>
194         public void updateScore(int s) {
195             this.scorce = this.scorce + s;
196         }
197
198         /// <summary>
199         /// 重置信息
200         /// </summary>
201         public void Reset() {
202             this.tetris = new int[10, 20];
203             this.scorce = 0;
204         }
205     }

5. 随机生成方块元素和起始位置

 1 /// <summary>
 2         /// 静态函数,生成Tetris元素对象
 3         /// </summary>
 4         /// <returns></returns>
 5         public static TetrisElement generate()
 6         {
 7             Random r = new Random(0);
 8             //随机生成形状
 9             int tstyle = getRandom();
10             tstyle = tstyle % 7;
11             TetrisStyle style = TetrisStyle.I;
12             style = (TetrisStyle)Enum.Parse(typeof(TetrisStyle), tstyle.ToString());
13             //随机生成起始坐标
14             int x = getRandom();
15             x = x % 10;
16             int y = 0;
17             //根据形状生成位置信息
18             TetrisElement element = new TetrisElement(style);
19             //内容由四个点组成,顺序:先上后下,先左后右
20             Point[] content = element.getContent(style);
21             //获取最小坐标和最大坐标,防止越界
22             int minX = element.getMinX(style);
23             int minY = element.getMinY(style);
24             int maxX = element.getMaxX(style);
25             int maxY = element.getMaxY(style);
26             //修正起始坐标
27             x = (x <= minX) ? minX : x;
28             x = (x >= maxX) ? maxX : x;
29             y = minY;
30             Point location = new Point(x, y);
31             element.location = location;
32             element.content = content;
33             return element;
34         }

备注

源码下载链接

闲下来的时候,放一段柔情音乐,翻阅几页好书,然后睡个懒觉,快哉。

转载于:https://www.cnblogs.com/hsiang/p/11415810.html

C# 实现俄罗斯方块相关推荐

  1. python编的俄罗斯方块游戏下载_python写的俄罗斯方块游戏

    python写的俄罗斯方块游戏 功能包括:记录所花费时间;消去的总行数;总分;排行榜,最高记录查看等. 排行榜中包含一系列的统计功能,如单位时间消去的行数,单位时间得分等. from Tkinter ...

  2. GitHub开源的超逼真俄罗斯方块游戏

    俄罗斯方块一直是各类程序语言热衷实现的经典游戏,有很多JavaScript实现版本,本开源项目使用React实现. 项目试玩网址:https://chvin.github.io/react-tetri ...

  3. Python实现俄罗斯方块

    目录 1.外形设计 2.方块设计 3.停靠设计 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很难啊,等真正写完了发现 ...

  4. AI玩俄罗斯方块(Python实现)

    目录 1.环境 2.实现机制(Pierre Dellacherie算法) 3.代码实现 人工智能大火的今天,如果还是自己玩俄罗斯方块未免显得太LOW,为什么不对游戏升级,让机器自己去玩俄罗斯方块呢?有 ...

  5. 如何让AI教机器自己玩俄罗斯方块?

    作者 | Ahab 转载自公众号Ahab杂货铺(ID:PythonLearningCamp) 人工智能大火的今天,如果还是自己玩俄罗斯方块未免显得太 LOW,为什么不对游戏升级,让机器自己去玩俄罗斯方 ...

  6. 500行代码写一个俄罗斯方块游戏

    导读:本文我们要制作一个俄罗斯方块游戏. 01 俄罗斯方块 Tetris 俄罗斯方块游戏是世界上最流行的游戏之一.是由一名叫Alexey Pajitnov的俄罗斯程序员在1985年制作的,从那时起,这 ...

  7. 算法帖——用舞蹈链算法(Dancing Links)求解俄罗斯方块覆盖问题

    问题的提出:如下图,用13块俄罗斯方块覆盖8*8的正方形.如何用计算机求解? 解决这类问题的方法不一而足,然而核心思想都是穷举法,不同的方法仅仅是对穷举法进行了优化 用13块不同形状的俄罗斯方块(每个 ...

  8. python俄罗斯方块算法详解_用 Python 写一个俄罗斯方块游戏 (

    @@ -2,34 +2,34 @@ > * 原文作者:[Dr Pommes](https://medium.com/@pommes) > * 译文出自:[掘金翻译计划](https://g ...

  9. pygame简单的俄罗斯方块游戏和简单的打字游戏

    1.pygame简单的俄罗斯方块游戏 一.对战的方块管理 定义一个BlockManage管理对战的方块 根据BlockManage根据传入的玩家id返回方块,保证每个玩家拿到的方块序列是一致的,所以在 ...

  10. linux下c语言俄罗斯方块,C语言实现俄罗斯方块源代码

    本文实例为大家分享了C语言实现俄罗斯方块的具体代码,供大家参考,具体内容如下 Head.h #ifndef _HEAD_H_ #define _HEAD_H_ #include #include #i ...

最新文章

  1. python ffmpeg模块,python执行ffmpeg
  2. 一行代码,揭开CPU执行原理!
  3. 京东主图怎么保存原图_京东自营怎么做?详解京东平台操作方法
  4. Windows CE 6.0正式发布 源代码100%开放
  5. excel转kml工具_CAD+Excel还能这样玩?你用对了嘛!
  6. Java24-day15(完结)【反射(类加载器、反射)、反射获取构造方法-成员变量-成员方法、模块化(概述、模块基本使用、模块服务使用)】
  7. boost::iostreams::stream_offset用法的测试程序
  8. 【BZOJ4543】Hotel加强版【神仙树形dp】【长链剖分】
  9. AUTOSAR从入门到精通100讲(二十三)-AUTOSAR通信篇—PduR模块
  10. mysql数据库备份shell_mysql数据库备份shell脚本分享
  11. 浅谈opencl之错误码
  12. calendar获取本周一的日期_Java日期时间API系列1-----Jdk7及以前的日期时间类
  13. 清华毕业程序员国企干了14年,去应聘小公司,看到工资后愣了
  14. jenkins的administrator权限
  15. vue+element 获取中文首字母,转换成大写
  16. java gc内存_Java内存模型和GC机制
  17. html各种弹出框和提示框
  18. MIPI屏和LVDS屏有什么区别
  19. 基于MATLAB的农业病虫害识别系统
  20. 并发(concurrency)和并行(parallelism)的区别

热门文章

  1. 超算优化重在存储,DAOS助力瑞金打造先进的生信大数据平台
  2. 缓存架构技术:开课吧java高级架构师第七期笔记
  3. 微信红包封面热潮的背后思考
  4. 一步一步实现现代前端单元测试
  5. android 蓝牙发送失败怎么办,在Android中通过蓝牙发送文件时出错?
  6. SAS,软件使用中reg报错/gplot错误的解决方法。
  7. 皮卡丘0.1.5V.GPC无敌版
  8. 114DNS Public DNS+ 阿里DNS 百度DNS 360 DNS派 Google DNS公共DNS评测体验报告
  9. 数据分析师简介、工作任务、技能栈
  10. 职场内耗,正在让这个团队瓦解