C#之四十八 俄羅斯方塊設(shè)計

      網(wǎng)友投稿 751 2025-04-01

      1????????系統(tǒng)設(shè)計要求


      1.1???需求分析

      本系統(tǒng)為一個用C#實(shí)現(xiàn)的為我們所熟悉的簡單的俄羅斯方塊游戲,該系統(tǒng)的具體功能如下:

      1).???????能簡便的開始游戲,游戲中的方塊的功能與日常我們所熟悉的游戲的功能一致,各種塊的設(shè)置也一致,包括塊的旋轉(zhuǎn),加速下降,平移,滿行消去,到頂游戲結(jié)束功能;

      2).???????能夠自定義游戲中功能鍵的具體按鍵,顯示下一方塊提示信息,以及游戲數(shù)據(jù)的統(tǒng)計;

      3).???????考慮需要解決的問題:怎么樣設(shè)置圖形顯示;怎樣獲取鍵盤輸入;怎樣控制方塊的移動;怎樣控制時間間隔(用于游戲中控制形狀的下落);游戲中的各種形狀及整個游戲空間怎么用數(shù)據(jù)表示;游戲中怎么判斷左右及向下移動的可能性;游戲中怎么判斷某一形狀旋轉(zhuǎn)的可能性;按向下方向鍵時加速某一形狀下落速度的處理;怎么判斷某一形狀已經(jīng)到底;怎么判斷某一已經(jīng)被填滿;怎么消去已經(jīng)被填滿的一行;怎么消去某一形狀落到底后能夠消去的所有的行;(如長條最多可以消去四行)怎樣判斷游戲結(jié)束,關(guān)于“下一個”形狀取法的問題。

      2????????設(shè)計思路

      2.1???用面向?qū)ο?/a>的方法分析系統(tǒng)

      從游戲的基本玩法出發(fā),主要就是俄羅斯方塊的形狀和旋轉(zhuǎn),在設(shè)計中在一個圖片框中構(gòu)造了一個20*20(像素)的小塊,由這些小塊組合成新的形狀,每四個小塊連接在一起就可以構(gòu)造出一種造型,總共設(shè)計了7中造型,每種造型又可以通過旋轉(zhuǎn)而變化出2到4種形狀,在游戲窗體中用戶就可以使用鍵盤的方向鍵來控制方塊的運(yùn)動,然后對每一行進(jìn)行判斷,如果有某行的方塊是滿的,則消除這行的方塊,并且使上面的方塊自由下落,其中,方塊向下的速度是有時鐘控件控制的。俄羅斯方塊游戲設(shè)計主要包括以下10個方面:

      1).?????????游戲界面的設(shè)計。

      2).?????????俄羅斯方塊的實(shí)現(xiàn)。

      3).?????????鍵盤輸入信息的獲取。

      4).?????????俄羅斯方塊的移動(向左,向右和向下)。

      5).?????????俄羅斯方塊的變換。

      6).?????????方塊自動下落與速度的選擇。

      7).?????????慢行的判斷與消行。

      8).?????????游戲結(jié)束判斷。

      9).?????????用戶配置保存。

      在主窗口中,通過調(diào)用俄羅斯方塊類來實(shí)現(xiàn)程序的表示層,在該窗口中通過兩個Panel控件來實(shí)現(xiàn)方塊疊放窗口和下一方塊信息窗口;調(diào)用設(shè)置窗口,保存設(shè)計窗口類傳回的信息,并設(shè)置到游戲中去,保存在配置文件中;

      在設(shè)置窗口中,以良好的界面提供用戶自定義快捷鍵的接口,保存相應(yīng)設(shè)置參數(shù),以提供給調(diào)用窗口。

      2.2運(yùn)用的控件和主要對象

      在設(shè)計過程中主要用到的控件有:PictureBox控件,MenuStrip控件,Button控件,Label控件,Timer控件,winmm組件,DirectSound等等。

      3????????系統(tǒng)功能實(shí)現(xiàn)

      3.1???屏幕信息初始化

      用來顯示狀態(tài)信息的框

      privateSystem.Windows.Forms.GroupBox statusBox;

      開始按鈕

      privateSystem.Windows.Forms.Button btnStart;

      顯示“下一塊”的標(biāo)簽

      privateSystem.Windows.Forms.Label label3;

      顯示“分?jǐn)?shù)”的標(biāo)簽

      privateSystem.Windows.Forms.Label label2;

      顯示“等級”的標(biāo)簽

      privateSystem.Windows.Forms.Label label1;

      用來畫下一塊方塊的區(qū)域

      privateSystem.Windows.Forms.PictureBox panel1;

      游戲區(qū)域

      privateSystem.Windows.Forms.PictureBox gameArea;

      實(shí)現(xiàn)如下主界面效果圖(圖3-1):

      1.1???方塊的實(shí)現(xiàn)

      在程序中每一個方塊都是一個Block類的實(shí)例。Block包括的參數(shù)有方塊的寬度,高度,最左端橫坐標(biāo),最上端縱坐標(biāo),方塊的數(shù)組表示。其中一共有7中形狀的方塊,以數(shù)組表示為:

      11???? 11????1???? ??11???? 010????10???? 01

      01???? 10????1?????? 11??? ?111???? 11????11

      01???? 10????1????????????????????? 01? ???10

      1

      方塊的7種形狀分別以數(shù)字0-6來代表,在構(gòu)造函數(shù)中,隨機(jī)生成0-6中數(shù)字,以此來隨機(jī)生成方塊的形狀。用來在界面上顯示方塊的貼圖也以0-6的數(shù)字來代表,同樣以隨機(jī)數(shù)的形式來隨機(jī)的現(xiàn)實(shí)方塊的顏色。

      1.2???鍵盤輸入事件處理

      因?yàn)樵诮缑嫔嫌幸粋€按鈕,并且只有一個按鈕,所以該按鈕在通常情況下都是默認(rèn)為焦點(diǎn)。在這種情況下按下某些鍵,比如空格,就會產(chǎn)生出發(fā)按鈕事件的情況。因此必須重載整個WinForm的ProcessCmdKey來避免這樣的問題。

      當(dāng)按向左,向右及旋轉(zhuǎn)按鈕時,只要相應(yīng)的處理方塊的位置或者形狀即可,但是當(dāng)按向下或者立即下落時,需要不同的處理。向下移動時,如果移動到最底部但還未固定,則需要重新設(shè)置計時器間隔時間,從而使自動下落時,底部未固定的方塊到固定的時間相同。如果方塊在最底部而未固定的時候,向下移動,則立即固定。這兩種情況,當(dāng)方塊固定后,都需要判斷是否消行,立即下落時,需要判斷是否消行。

      1.3???方塊的移動

      游戲中方塊的移動分為向左移動,向右移動,向下移動和立即落下。

      向左移動:

      public void MoveLeft() {

      int xPos =runBlock.XPos-1;

      intyPos = runBlock.YPos;

      for(int i = 0; i < runBlock.Length; i++)

      {

      if(xPos + runBlock[i].X <0)//如果超出左邊界則失敗

      {

      return;

      }

      if(!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)//如果左邊有東西擋則失敗

      {

      return;

      }

      }

      runBlock.erase(gpPaltte);//擦除原來位置的轉(zhuǎn)塊

      runBlock.XPos--;

      runBlock.Paint(gpPaltte);//在新位置上畫轉(zhuǎn)塊

      }

      向右移動:

      public void MoveRight()

      {

      intxPos = runBlock.XPos + 1;

      intyPos = runBlock.YPos;

      for(int i = 0; i < runBlock.Length; i++)

      {

      if(xPos + runBlock[i].X >_width-1)//如果超出右邊界則失敗

      {

      return;

      }

      if(!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)//如果右邊有東西擋則失敗

      {

      return;

      }

      }

      runBlock.erase(gpPaltte);//擦除原來位置的轉(zhuǎn)塊

      runBlock.XPos++;

      runBlock.Paint(gpPaltte);//在新位置上畫轉(zhuǎn)塊

      }

      向下移動:

      public void Drop() {

      timerBlock.Stop();

      while(Down()) ;

      timerBlock.Start();

      }

      1.4???方塊的變換

      public voidDeasilRotate() //順時針旋轉(zhuǎn)

      {

      for (int i = 0; i< runBlock.Length;i++ )

      {

      int x = runBlock.XPos + runBlock[i].Y;

      int y = runBlock.YPos + runBlock[i].X;

      if (x < 0 || x > _width - 1)//如果超出左右邊界,則失敗

      return;

      if (y < 0 || y > _height - 1)//如果超出上下邊界,則失敗

      return;

      if (!coorArr[x, y].IsEmpty)//如果旋轉(zhuǎn)后的位置上有轉(zhuǎn)塊,則失敗

      return;

      }

      runBlock.erase(gpPaltte);//擦除原來位置的轉(zhuǎn)塊

      runBlock.DeasilRotate();

      runBlock.Paint(gpPaltte);//在新位置上畫轉(zhuǎn)塊

      }

      public voidContraRotate() //逆時針旋轉(zhuǎn)

      {

      for (int i = 0; i< runBlock.Length; i++)

      {

      int x = runBlock.XPos - runBlock[i].Y;

      int y = runBlock.YPos - runBlock[i].X;

      if (x < 0 || x > _width - 1)//如果超出左右邊界,則失敗

      return;

      if (y < 0|| y > _height - 1)//如果超出上下邊界,則失敗

      return;

      if (!coorArr[x, y].IsEmpty)//如果旋轉(zhuǎn)后的位置上有轉(zhuǎn)塊,則失敗

      return;

      }

      runBlock.erase(gpPaltte);//擦除原來位置的轉(zhuǎn)塊

      runBlock.ContraRotate();

      runBlock.Paint(gpPaltte);//在新位置上畫轉(zhuǎn)塊

      }

      1.5???判斷方塊是否到底

      public voidCheckAndOverBlock()//檢查轉(zhuǎn)塊是否到底,如果到底則把當(dāng)前轉(zhuǎn)塊歸入coorArr,并產(chǎn)生新的轉(zhuǎn)塊

      {

      boolover = false;//設(shè)置一個當(dāng)前運(yùn)行轉(zhuǎn)塊是否到底的標(biāo)志

      for(int i = 0; i < runBlock.Length;i++ )//遍歷當(dāng)前運(yùn)行轉(zhuǎn)塊的所有小方塊

      {

      intx = runBlock.XPos + runBlock[i].X;

      inty = runBlock.YPos - runBlock[i].Y;

      if(y == _height - 1)//如果到達(dá)下邊界,則結(jié)束當(dāng)前轉(zhuǎn)塊

      {

      over = true;

      break;

      }

      if(!coorArr[x, y+1].IsEmpty) //如果下面有轉(zhuǎn)塊,則當(dāng)前轉(zhuǎn)塊結(jié)束

      {

      over = true;

      break;

      }

      }

      if(over)

      {

      for(int i = 0; i < runBlock.Length; i++)//把當(dāng)前轉(zhuǎn)塊歸入coordinateArr

      {

      coorArr[runBlock.XPos +runBlock[i].X, runBlock.YPos - runBlock[i].Y] = runBlock.BlockColor;

      }

      //檢查是否有滿行情況,如果有則刪除

      CheckAndDelFullRow();

      //產(chǎn)生新轉(zhuǎn)塊

      runBlock = readyBlock;//新的轉(zhuǎn)塊為準(zhǔn)備好的轉(zhuǎn)塊

      runBlock.XPos = _width / 2;//確定當(dāng)前運(yùn)行轉(zhuǎn)塊的出生位置

      int y = 0;//確定轉(zhuǎn)塊Ypos,確定剛出生的轉(zhuǎn)塊頂上沒空行

      for (int i = 0; i < runBlock.Length; i++)

      {

      if (runBlock[i].Y > y)

      y = runBlock[i].Y;

      }

      runBlock.YPos = y;

      //檢查新生成的轉(zhuǎn)塊所占用的地方是否已經(jīng)有轉(zhuǎn)塊存在,如果有,游戲結(jié)束

      for (int i = 0; i

      {

      if (!coorArr[runBlock.XPos+ runBlock[i].X, runBlock.YPos - runBlock[i].Y].IsEmpty)

      {

      StringFormat drawFormat= new StringFormat();

      drawFormat.Alignment =StringAlignment.Center;

      gpPaltte.DrawString("GAME OVER",

      newFont("Arial Black", 25f),

      newSolidBrush(Color.White),

      newRectangleF(0, _height * rectPix / 2 - 100, _width * rectPix, 100),

      drawFormat);

      timerBlock.Stop();//關(guān)閉定時器

      return;

      }

      }

      runBlock.Paint(gpPaltte);

      //獲取新的準(zhǔn)備轉(zhuǎn)塊

      readyBlock = bGroup.GetABlock();

      readyBlock.XPos = 2;

      readyBlock.YPos = 2;

      gpReady.Clear(Color.Black);

      readyBlock.Paint(gpReady);

      }

      }

      1.6???滿行判斷并消行

      privatevoid CheckAndDelFullRow() //檢查并刪除滿行

      {

      //找出當(dāng)前轉(zhuǎn)塊所在行的范圍

      int lowRow = runBlock.YPos - runBlock[0].Y;//lowRow代表當(dāng)前轉(zhuǎn)塊的y軸的最小值

      int highRow = lowRow;//highRow代表當(dāng)前轉(zhuǎn)塊y軸的最大值

      for (int i = 0; i < runBlock.Length; i++)//找出當(dāng)前轉(zhuǎn)塊所占行的范圍,放入low和high變量內(nèi)

      {

      int y = runBlock.YPos - runBlock[i].Y;

      if (y < lowRow)

      lowRow = y;

      if (y > highRow)

      highRow = y;

      }

      bool repaint = false;//判斷是否重畫標(biāo)志

      for (int i = lowRow; i <= highRow; i++) //檢查是否滿行,如果有,則刪除

      {

      bool rowFull = true;

      for (int j = 0; j < _width;j++ )

      {

      if (coorArr[j,i].IsEmpty)//如果有一行為空,則說明這行不滿

      {

      rowFull = false;

      break;

      }

      }

      if (rowFull) //如果是滿行,則刪除這一行

      {

      repaint = true;//如果有要刪除的行,則需要重畫

      for (int k = i; k > 0;k--) {//把第n行的值用n-1行的值來代替

      for (int j = 0; j <_width; j++) {

      coorArr[j, k] =coorArr[j, k - 1];

      }

      }

      for (int j = 0; j <_width;j++ )//清空第0行

      {

      coorArr[j, 0] = Color.Empty;

      }

      }

      }

      if(repaint)//重畫

      {

      PaintBackground(gpPaltte);

      }

      }

      3.8? 產(chǎn)生下一方塊

      public bool GeneBlock(int shapeNO, Point firstPos, Colorcolor)//產(chǎn)生下一方塊

      {

      this.SetLastPos();

      this.EraseLast();

      this.SetPos(shapeNO,firstPos);

      if(!this.CanRotate(this.pos))

      {

      this.pos=null;

      returnfalse;

      }

      else

      {

      this.color=color;

      returntrue;

      }

      }

      3.9????????游戲設(shè)置

      保存配置

      private void SaveSetting()

      {

      try

      {

      XmlDocumentdoc = new XmlDocument();

      XmlDeclarationxmlDec=doc.CreateXmlDeclaration ("1.0","gb2312",null);

      XmlElementsetting=doc.CreateElement("SETTING");

      doc.AppendChild(setting);

      XmlElementlevel=doc.CreateElement("LEVEL");

      level.InnerText=this.startLevel.ToString();

      setting.AppendChild(level);

      XmlElementtrans=doc.CreateElement("TRANSPARENT");

      C#之四十八 俄羅斯方塊設(shè)計

      trans.InnerText=this.trans.ToString();

      setting.AppendChild(trans);

      XmlElementkeys=doc.CreateElement("KEYS");

      setting.AppendChild(keys);

      foreach(Keysk in this.keys)

      {

      KeysConverterkc=new KeysConverter();

      XmlElementx=doc.CreateElement("SUBKEYS");

      x.InnerText=kc.ConvertToString(k);

      keys.AppendChild(x);

      }

      XmlElementroot=doc.DocumentElement;

      doc.InsertBefore(xmlDec,root);

      doc.Save("c:\\setting.cob");

      }

      catch(Exceptionxe)

      {

      MessageBox.Show(xe.Message);

      }

      }

      4? 總結(jié)

      本設(shè)計通過Vusial Studio 方便的Windows表單設(shè)計界面,增加了相應(yīng)的按鈕單擊響應(yīng)函數(shù),通過與用戶的交互,反饋回用戶所需要的信息。

      設(shè)計出的程序符合設(shè)計需求,既有基本的游戲邏輯功能,又能保存用戶的設(shè)置,取得較好的實(shí)驗(yàn)結(jié)果。

      這個學(xué)期“C#程序設(shè)計”課程讓我接觸了面向?qū)ο?/a>的程序設(shè)計,Visual stdio的可視化編程環(huán)境讓我們可以制作界面友好的Windows環(huán)境,利用IDE可以快捷地開發(fā)出所要的可視化的環(huán)境。C#是是一種完全面向?qū)ο蟮恼Z言,使用對象的思想來編程,既可以對相應(yīng)的數(shù)據(jù)進(jìn)行保護(hù),也可以相應(yīng)的與其他的類共享,有利于程序的結(jié)構(gòu)化,方面程序的編寫。Viusal Studio下我們可以快速的進(jìn)行開發(fā)。但是,也要看到其對WindowsApi函數(shù)的封裝也導(dǎo)致了我們在學(xué)習(xí)的時候?qū)indows程序的運(yùn)行機(jī)制不了解,導(dǎo)致了學(xué)習(xí)時候的迷惑。本學(xué)期配套的書籍<< C#實(shí)用教程>>雖然簡單明了,但是對于機(jī)制原理的解釋和說明過少,因此,學(xué)習(xí)的時候應(yīng)該不只滿足于這本書中的內(nèi)容,應(yīng)該多找一些書籍進(jìn)行知識的擴(kuò)展了加深。

      C#

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:數(shù)據(jù)統(tǒng)計表格怎么做(數(shù)據(jù)統(tǒng)計表格怎么做出來)
      下一篇:MMULT計算出來的結(jié)果為什么是#VALUE! ?而不是數(shù)值(mmult用法示例)
      相關(guān)文章
      亚洲福利电影在线观看| 久久久久亚洲av无码尤物| 亚洲天天在线日亚洲洲精| 青青草原亚洲视频| 亚洲一级片内射网站在线观看| 亚洲中文字幕无码mv| 亚洲中文无码av永久| 亚洲国产午夜精品理论片| 亚洲欧洲日产韩国在线| 亚洲国产成AV人天堂无码| 亚洲国产人成在线观看| 亚洲制服丝袜精品久久| 亚洲国产成人综合| 亚洲一区二区三区高清视频| 亚洲av无码专区在线| 久久精品国产亚洲av麻豆蜜芽| 33333在线亚洲| 亚洲va成无码人在线观看| 中文字幕亚洲综合小综合在线| 国产成+人+综合+亚洲专| 亚洲偷偷自拍高清| 午夜在线a亚洲v天堂网2019| 亚洲砖码砖专无区2023| 亚洲精品乱码久久久久久V| 亚洲a无码综合a国产av中文| heyzo亚洲精品日韩| 亚洲午夜激情视频| 亚洲色精品aⅴ一区区三区| 亚洲va无码va在线va天堂| 亚洲视频精品在线| 亚洲一区二区在线视频| 亚洲国产高清视频在线观看| 亚洲综合偷自成人网第页色| 亚洲精品又粗又大又爽A片| 日产国产精品亚洲系列| 国产成人精品日本亚洲专区61| 亚洲精品无码永久中文字幕| 蜜芽亚洲av无码精品色午夜| 亚洲国产成a人v在线观看 | 亚洲国产精品ⅴa在线观看| 精品国产亚洲一区二区三区在线观看 |