溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C#實(shí)現(xiàn)俄羅斯方塊的代碼詳解

發(fā)布時(shí)間:2020-07-17 17:32:25 來(lái)源:億速云 閱讀:408 作者:小豬 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要講解了C# 實(shí)現(xiàn)俄羅斯方塊的代碼詳解,內(nèi)容清晰明了,對(duì)此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會(huì)有幫助。

概述

俄羅斯方塊(Tetris)是一款由俄羅斯人阿列克謝·帕基特諾夫發(fā)明的休閑游戲,帕基特諾夫愛(ài)玩拼圖,從拼圖游戲里得到靈感,設(shè)計(jì)出了俄羅斯方塊。由于上手簡(jiǎn)單、老少皆宜,從而家喻戶曉,風(fēng)靡世界。本文簡(jiǎn)述如何通過(guò)C#來(lái)實(shí)現(xiàn)俄羅斯方塊,僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正。

涉及知識(shí)點(diǎn)

BackgroundWorker 在單獨(dú)的線程上執(zhí)行操作(主要執(zhí)行比較耗時(shí)的操作)。
Action .NetFramework自帶的一個(gè)委托方法。
TableLayoutPanel  表示一個(gè)面板,它可以在一個(gè)由行和列組成的網(wǎng)格中對(duì)其內(nèi)容進(jìn)行動(dòng)態(tài)布局,本文主要用作俄羅斯方塊的容器。

方塊流程圖

如下圖所示,描述了俄羅斯方塊的設(shè)計(jì)流程圖

C#實(shí)現(xiàn)俄羅斯方塊的代碼詳解

俄羅斯方塊效果圖

如下圖所示:主要包括狀態(tài),得分,開(kāi)始按鈕,停止按鈕,按鍵盤(pán)左右箭頭移動(dòng)等功能

C#實(shí)現(xiàn)俄羅斯方塊的代碼詳解

核心代碼

1. 定義方塊的形狀

如下所示:共7中形狀

/// <summary>
 /// 俄羅斯方塊的形狀
 /// </summary>
 public enum TetrisStyle
 {
  S = 0,
  Z = 1,
  L = 2,
  J = 3,
  I = 4,
  O = 5,
  T = 6
 }

2. 定義移動(dòng)的方向

如下所示:默認(rèn)向下移動(dòng),同時(shí)可以左右移動(dòng)

/// <summary>
 /// 俄羅斯方塊移動(dòng)方向
 /// </summary>
 public enum TetrisDirection
 {
  UP = 0,//上,表示順時(shí)針旋轉(zhuǎn)
  DOWN = 1,//下,表示向下移動(dòng)
  LEFT = 2,//左,表示往左移動(dòng)
  RIGHT = 3, //表示向右移動(dòng)
  DEFAULT=4 //默認(rèn)動(dòng)作
 }

3. 俄羅斯方塊元素
如下所示,每一種形狀都由四個(gè)方塊組成,根據(jù)不同形狀設(shè)置不同的位置

 /// <summary>
  /// 俄羅斯方塊元素
  /// </summary>
  public class TetrisElement
  {
   /// <summary>
   /// 構(gòu)造函數(shù)
   /// </summary>
   /// <param name="style"></param>
   public TetrisElement(TetrisStyle style) {
    this.style = style;
   }
 
   /// <summary>
   /// 構(gòu)造函數(shù)
   /// </summary>
   /// <param name="style">形狀</param>
   /// <param name="content">內(nèi)容</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>
   /// 內(nèi)容
   /// </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)
   {
    //內(nèi)容由四個(gè)點(diǎn)組成,順序:先上后下,先左后右
    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:
      //默認(rèn)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. 容器類
如下所示:容器類主要是移動(dòng)方塊元素,并更新頁(yè)面上的值

/// <summary>
 /// 俄羅斯方塊容器
 /// </summary>
 public class TetrisContainer
 {
  private int[,] tetris = new int[10, 20];//定義二維數(shù)組,表示坐標(biāo)信息,默認(rèn)值為0

  public Action<Point,Point[],TetrisDirection> onPartialChanged;//局部變更事件

  public Action<int[,]> onFullChanged;//元素全變更事件,即有整行被清除事件

  public Action onCompleted; //結(jié)束事件

  public int scorce = 0;

  /// <summary>
  /// 狀態(tài)發(fā)生改變
  /// </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:
     //如果可以向下移動(dòng)
     if (checkDefault(element))
     {
      //向下移動(dòng)一個(gè)元素
      element.move(element.location.X, element.location.Y + 1);
      tmp = element;
     }
     else {
      //如果不可以向下移動(dòng),則更新容器
      updateTetris(element);
      tmp = null;
     }

     break;
    case TetrisDirection.DOWN:
     break;
    case TetrisDirection.UP:
     break;
    case TetrisDirection.LEFT:
     if (checkLeft(element)){
      //判斷是否可以向左移動(dòng)
      //向下移動(dòng)一個(gè)元素
      element.move(element.location.X-1, element.location.Y);
      tmp = element;
     }
     break;
    case TetrisDirection.RIGHT:
     if (checkRight(element))
     {
      //判斷是否可以右左移動(dòng)
      //向下移動(dòng)一個(gè)元素
      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);
   }

   //判斷游戲是否結(jié)束
   if (onCompleted != null) {
    if (checkComplete()) {
     onCompleted();
    }
   }

   //全部變更
   if (onFullChanged != null)
   {
    //判斷是是否有權(quán)為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) {
    //當(dāng)前行清掉
    for (int x = 0; x < 10; x++) {
     tetris[x, row] = 0;
    }
    //row行之上的往下移動(dòng)一行
    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>
  /// 判斷游戲是否結(jié)束
  /// </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. 隨機(jī)生成方塊元素和起始位置

/// <summary>
  /// 靜態(tài)函數(shù),生成Tetris元素對(duì)象
  /// </summary>
  /// <returns></returns>
  public static TetrisElement generate()
  {
   Random r = new Random(0);
   //隨機(jī)生成形狀
   int tstyle = getRandom();
   tstyle = tstyle % 7;
   TetrisStyle style = TetrisStyle.I;
   style = (TetrisStyle)Enum.Parse(typeof(TetrisStyle), tstyle.ToString());
   //隨機(jī)生成起始坐標(biāo)
   int x = getRandom();
   x = x % 10;
   int y = 0;
   //根據(jù)形狀生成位置信息
   TetrisElement element = new TetrisElement(style);
   //內(nèi)容由四個(gè)點(diǎn)組成,順序:先上后下,先左后右
   Point[] content = element.getContent(style);
   //獲取最小坐標(biāo)和最大坐標(biāo),防止越界
   int minX = element.getMinX(style);
   int minY = element.getMinY(style);
   int maxX = element.getMaxX(style);
   int maxY = element.getMaxY(style);
   //修正起始坐標(biāo)
   x = (x <= minX) &#63; minX : x;
   x = (x >= maxX) &#63; maxX : x;
   y = minY;
   Point location = new Point(x, y);
   element.location = location;
   element.content = content;
   return element;
  }

看完上述內(nèi)容,是不是對(duì)C# 實(shí)現(xiàn)俄羅斯方塊的代碼詳解有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI