zoukankan      html  css  js  c++  java
  • C# 实现俄罗斯方块

    概述

    俄罗斯方块(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         }

    备注

    源码下载链接

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

  • 相关阅读:
    一篇文章读懂JSON
    不该被忽视的CoreJava细节(四)
    Java面试题总结(二)
    Java面试题总结(一)
    不该被忽视的CoreJava细节(三)
    不该被忽视的CoreJava细节(一)
    逐步解读String类(一)
    JSP注释格式
    命令行启动mysql服务
    经典进程的同步问题之——生产者&&消费者
  • 原文地址:https://www.cnblogs.com/hsiang/p/11415810.html
Copyright © 2011-2022 走看看