2017年11月13日 星期一

用C# 寫經典遊戲: TETRIS 俄羅斯方塊(魔術方塊) 完整程式碼 (Full Source Code)

       
        用C#寫出經典遊戲:俄羅方塊(又名魔術方塊,TETRIS)?乍聽之下,好想頗複雜,但是實際上,你只要會幾個簡單的語法,就可以順利的把它實做出來。


 
先來看看執行的情況 !!!



  如果你真的很有興趣,想要自己動手做,那麼就 ...
下載完整程式碼 (download full source code)


         首先,讓我們來構思一下,俄羅斯方塊顯示的部分,該用什麼來實作呢? 我採取了最簡單的Label(標籤)來完成,可是需要用總共200個Label,什麼?200個?你沒看錯,因為我們的俄羅斯方塊總共有20(列) X 10(行)個格子,你可以直接使用Visual Studio內的設計工具,拉出200個Label(那好累喔!),也可以使用程式動態產生(嗯,這個比較好!),然後再用程式把他們在視窗(Form)上面排好,OK! 這樣顯示的部分就完成了,就像這樣:
         
Label[,] grids = new Label[20,10]; //main area, total 200 grids 

for (int i = 0; i < 20; i++)
    for (int j = 0; j < 10; j++)
    {
         grids[i, j] = new Label();
         grids[i, j].Width = 30;
         grids[i, j].Height = 30;
         grids[i, j].BorderStyle = BorderStyle.FixedSingle;
         grids[i, j].BackColor = Color.Black;                    
         grids[i, j].Left = 150 + 30 * j;
         grids[i, j].Top = 600 - i * 30;
         grids[i, j].Visible = true;
         this.Controls.Add(grids[i, j]);
    }


好啦,接下來當然就是"俄羅斯方塊"本尊了,俄羅斯方塊總共有七種,


Type 1

Type 2


Type 3


Type 4


Type 5


Type 6


Type 7

當方塊出現在最上方時,就只有這七種形式,但是在翻轉之後,會產生其他形式(黑點為參考點,紅點為旋轉支點,沒有紅點者即以參考點為支點):


  ( 順時鐘轉)
    type 1         type 11

  ( 不旋轉)
        type 2

  ( 逆時鐘轉)
         type 3                 type 13

 ( 逆時鐘轉)
        type 4                    type 14

 ( 逆時鐘轉)
       type 5                    type 15                type 25               type 35

  ( 順時鐘轉)
          type 6                   type 16             type 26                 type 36

  ( 順時鐘轉)
         type 7                 type 17                 type 27               type 37

以上是我的旋轉規則和分類方式,你也可以改用你喜歡的方式,It's up to you.
分類完之後,就要開始寫程式了:我用了幾個全域變數紀錄遊戲進行的狀況,包括一個24x10的二維陣列(bool Array),紀錄那些格點被佔用了,還有現在正掉落的的方塊的型態和參考點位置,當然你還得啟動一個計時器,由計時器的tick來觸發方塊的掉落,當方塊觸底或被之前的方塊擋住時,就要馬上停止,並啟動下一個方塊。

這個函數根據方塊的型態,和位置,將它紀錄在格點中
void update_block(uint i, uint j, uint type)
{
    switch (type)
   {
                case 1: 
                    signs[i, j] = signs[i+1, j] = signs[i+2, j] = signs[i+3, j] = true;
                    grids_color[i, j] = grids_color[i + 1, j] = grids_color[i + 2, j] = grids_color[i + 3, j] = Color.Blue;
                    break;
                case 11: 
                    signs[i, j] = signs[i, j+1] = signs[i, j+2] = signs[i, j+3] = true;
                    grids_color[i, j] = grids_color[i, j + 1] = grids_color[i, j + 2] = grids_color[i, j + 3] = Color.Blue;
                    break;
               case 2:
                    signs[i, j] = signs[i + 1, j] = signs[i , j+1] = signs[i + 1, j+1] = true;
                    grids_color[i, j] = grids_color[i + 1, j] = grids_color[i, j + 1] = grids_color[i + 1, j + 1] = Color.Yellow;
                    break;
               case 3:
                    signs[i, j] = signs[i + 1, j] = signs[i+1, j-1] = signs[i, j + 1] = true;
                    grids_color[i, j] = grids_color[i + 1, j] = grids_color[i + 1, j - 1] = grids_color[i, j + 1] = Color.Red;
                    break;
               case 13:
                    signs[i, j] = signs[i - 1, j] = signs[i , j + 1] = signs[i+1, j + 1] = true;
                    grids_color[i, j] = grids_color[i - 1, j] = grids_color[i, j + 1] = grids_color[i + 1, j + 1] = Color.Red;
                    break;
               case 4:
                    signs[i, j] = signs[i , j-1] = signs[i + 1, j] = signs[i+1, j + 1] = true;
                    grids_color[i, j] = grids_color[i, j - 1] = grids_color[i + 1, j] = grids_color[i + 1, j + 1] = Color.Green;
                    break;
               case 14:
                    signs[i, j] = signs[i+1, j] = signs[i, j+1] = signs[i-1, j + 1] = true;
                    grids_color[i, j] = grids_color[i + 1, j] = grids_color[i, j + 1] = grids_color[i - 1, j + 1] = Color.Green;
                    break;
               case 5:
                    signs[i, j] = signs[i+1, j] = signs[i + 1, j+1] = signs[i + 1, j + 2] = true;
                    grids_color[i, j] = grids_color[i + 1, j] = grids_color[i + 1, j + 1] = grids_color[i + 1, j + 2] = Color.Orange;
                    break;
               case 15:
                    signs[i, j] = signs[i, j-1] = signs[i + 1, j - 1] = signs[i + 2, j -1] = true;
                    grids_color[i, j] = grids_color[i, j - 1] = grids_color[i + 1, j - 1] = grids_color[i + 2, j - 1] = Color.Orange;
                    break;
               case 25:
                    signs[i, j] = signs[i-1, j] = signs[i - 1, j - 1] = signs[i -1, j - 2] = true;
                    grids_color[i, j] = grids_color[i - 1, j] = grids_color[i - 1, j - 1] = grids_color[i - 1, j - 2] = Color.Orange;
                    break;
               case 35:
                    signs[i, j] = signs[i, j+1] = signs[i - 1, j + 1] = signs[i - 2, j +1] = true;
                    grids_color[i, j] = grids_color[i, j + 1] = grids_color[i - 1, j + 1] = grids_color[i - 2, j + 1] = Color.Orange;
                    break;
               case 6:
                    signs[i, j] = signs[i + 1, j] = signs[i + 1, j - 1] = signs[i + 1, j - 2] = true;
                    grids_color[i, j] = grids_color[i + 1, j] = grids_color[i + 1, j - 1] = grids_color[i + 1, j - 2] = Color.LightBlue;
                    break;
               case 16:
                    signs[i, j] = signs[i, j+1] = signs[i + 1, j + 1] = signs[i + 2, j + 1] = true;
                    grids_color[i, j] = grids_color[i, j + 1] = grids_color[i + 1, j + 1] = grids_color[i + 2, j + 1] = Color.LightBlue;
                    break;
               case 26:
                    signs[i, j] = signs[i-1, j] = signs[i-1, j + 1] = signs[i -1, j + 2] = true;
                    grids_color[i, j] = grids_color[i - 1, j] = grids_color[i - 1, j + 1] = grids_color[i - 1, j + 2] = Color.LightBlue;
                    break;
               case 36:
                    signs[i, j] = signs[i, j-1] = signs[i - 1, j - 1] = signs[i - 2, j -1] = true;
                    grids_color[i, j] = grids_color[i, j - 1] = grids_color[i - 1, j - 1] = grids_color[i - 2, j - 1] = Color.LightBlue;
                    break;

               case 7:
                    signs[i, j] = signs[i, j-1] = signs[i, j+1] = signs[i+1, j] = true;
                    grids_color[i, j] = grids_color[i, j - 1] = grids_color[i, j + 1] = grids_color[i + 1, j] = Color.Purple;
                    break;
               case 17:
                    signs[i, j] = signs[i, j + 1] = signs[i-1, j] = signs[i + 1, j] = true;
                    grids_color[i, j] = grids_color[i, j + 1] = grids_color[i - 1, j] = grids_color[i + 1, j] = Color.Purple;
                    break;
               case 27:
                    signs[i, j] = signs[i, j - 1] = signs[i, j+1] = signs[i - 1, j] = true;
                    grids_color[i, j] = grids_color[i, j - 1] = grids_color[i, j + 1] = grids_color[i - 1, j] = Color.Purple;
                    break;
               case 37:
                    signs[i, j] = signs[i, j - 1] = signs[i+1, j] = signs[i - 1, j] = true;
                    grids_color[i, j] = grids_color[i, j - 1] = grids_color[i + 1, j] = grids_color[i - 1, j] = Color.Purple;
                    break;
            }
        }

這個函數偵測垂直方向是否已經落底或有障礙物:

bool y_direction(uint type, uint i, uint j)
{
     switch (type)
     {
                case 1:
                    if (i != 0 && !signs[i-1, j]) return true;
                    else return false;

                case 11:
                    if (i != 0 && !signs[i - 1, j] && !signs[i - 1, j + 1] && !signs[i - 1, j + 2] && !signs[i - 1, j + 3]) return true;
                    else return false;

                case 2:
                    if (i != 0 && !signs[i-1, j] && !signs[i-1, j+1]) return true;
                    else return false;

                case 3:
                    if (i != 0 && !signs[i, j-1] && !signs[i-1, j] && !signs[i-1, j+1]) return true;
                    else return false;

                case 13:
                    if (i != 1 && !signs[i-2, j] && !signs[i-1, j+1])  return true;
                    else return false;

                case 4:
                    if (i != 0 && !signs[i, j+1] && !signs[i-1, j] && !signs[i-1, j-1]) return true;
                    else return false;

                case 14:
                    if (i != 1 && !signs[i-1, j] && !signs[i-2, j+1]) return true;
                    else return false;

                case 5:
                    if (i != 0 && !signs[i-1, j] && !signs[i, j+1] && !signs[i, j+2]) return true;
                    else return false;

                case 15:
                    if (i != 0 && !signs[i - 1, j] && !signs[i-1, j-1]) return true;
                    else return false;

                case 25:
                    if (i != 1 && !signs[i - 2, j] && !signs[i - 2, j - 1] && !signs[i - 2, j - 2]) return true;
                    else return false;

                case 35:
                    if (i != 2 && !signs[i - 1, j] && !signs[i - 3, j + 1]) return true;
                    else return false;

                case 6:
                    if (i != 0 && !signs[i, j-1] && !signs[i, j-2] && !signs[i-1, j]) return true;
                    else return false;

                case 16:
                    if (i != 0 && !signs[i-1, j] && !signs[i-1, j+1]) return true;
                    else return false;
                    
                case 26:
                    if (i != 1 && !signs[i-2, j] && !signs[i-2, j + 1] && !signs[i-2, j+2]) return true;
                    else return false;
                    
                case 36:
                    if (i != 2 && !signs[i-1, j] && !signs[i-3, j-1]) return true;
                    else return false;
                    
                case 7:
                    if (i != 0 && !signs[i-1, j-1] && !signs[i-1, j] && !signs[i-1, j+1]) return true;
                    else return false;
                    
                case 17:
                    if (i != 1 && !signs[i-2, j] && !signs[i - 1, j+1]) return true;
                    else return false;
                    
                case 27:
                    if (i != 1 && !signs[i - 1, j - 1] && !signs[i - 1, j + 1] && !signs[i - 2, j]) return true;
                    else return false;
                    
                case 37:
                    if (i != 1 && !signs[i-2, j] && !signs[i-1, j-1]) return true;
                    else return false;

                default:
                    return false;                  
            }
        }


這個函數偵測水平方向是否有障礙物:

bool x_direction(uint type, uint i, uint j, int d)
     switch(type)
    {
               case 1:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j - 1] && !signs[i + 1, j - 1] && !signs[i + 2, j - 1] && !signs[i + 3, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 9 && !signs[i, j + 1] && !signs[i + 1, j + 1] && !signs[i + 2, j + 1] && !signs[i + 3, j + 1]) return true;
                       else return false;
                   }

               case 11:
                   if (d == -1) 
                   {
                       if (j != 0 && !signs[i, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 6 && !signs[i, j + 4]) return true;
                       else return false;
                   }
               
               case 2:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j - 1] && !signs[i + 1, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i + 1, j + 2]) return true;
                       else return false;
                   }

               case 3:
                   if (d == -1)
                   {
                       if (j != 1 && !signs[i, j - 1] && !signs[i + 1, j - 2]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i + 1, j + 1]) return true;
                       else return false;
                   }

               case 13:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j - 1] && !signs[i + 1, j] && !signs[i + 1, j-1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i + 1, j + 2] && !signs[i - 1, j + 1]) return true;
                       else return false;
                   }

               case 4:
                   if (d == -1)
                   {
                       if (j != 1 && !signs[i, j - 2] && !signs[i + 1, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 1] && !signs[i + 1, j + 2]) return true;
                       else return false;
                   }
                  
               case 14:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j-1] && !signs[i+1, j-1] && !signs[i-1, j]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i + 1, j + 1] && !signs[i-1, j + 2]) return true;
                       else return false;
                   }

               case 5:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j - 1] && !signs[i + 1, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 7 && !signs[i, j + 1] && !signs[i + 1, j + 3]) return true;
                       else return false;
                   }

               case 15:
                   if (d == -1)
                   {
                       if (j != 1 && !signs[i, j - 2] && !signs[i + 1, j - 2] && !signs[i + 2, j - 2]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 9 && !signs[i, j + 1] && !signs[i + 1, j] && !signs[i + 2, j]) return true;
                       else return false;
                   }
              
               case 25:
                   if (d == -1)
                   {
                       if (j != 2 && !signs[i, j-1] && !signs[i-1, j-3]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 9 && !signs[i, j + 1] && !signs[i-1, j+1]) return true;
                       else return false;
                   }
                
               case 35:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j - 1] && !signs[i-1, j] && !signs[i-2, j]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i-1, j+2] && !signs[i-2, j+2]) return true;
                       else return false;
                   }

               case 6:
                   if (d == -1)
                   {
                       if (j != 2 && !signs[i, j - 1] && !signs[i + 1, j - 3]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 9 && !signs[i, j + 1] && !signs[i + 1, j + 1]) return true;
                       else return false;
                   }

               case 16:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j - 1] && !signs[i + 1, j] && !signs[i + 2, j]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i + 1, j + 2] && !signs[i + 2, j + 2]) return true;
                       else return false;
                   }

               case 26:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j - 1] && !signs[i - 1, j-1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 7 && !signs[i, j + 1] && !signs[i - 1, j + 3]) return true;
                       else return false;
                   }

               case 36:
                   if (d == -1)
                   {
                       if (j != 1 && !signs[i, j - 2] && !signs[i - 1, j - 2] && !signs[i - 2, j - 2]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 9 && !signs[i, j + 1] && !signs[i - 1, j] && !signs[i - 2, j]) return true;
                       else return false;
                   }

               case 7:
                   if (d == -1)
                   {
                       if (j != 1 && !signs[i, j - 2] && !signs[i + 1, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i + 1, j + 1]) return true;
                       else return false;
                   }

               case 17:
                   if (d == -1)
                   {
                       if (j != 0 && !signs[i, j - 1] && !signs[i + 1, j - 1] && !signs[i - 1, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i + 1, j + 1] && !signs[i - 1, j + 1]) return true;
                       else return false;
                   }

               case 27:
                   if (d == -1)
                   {
                       if (j != 1 && !signs[i, j - 2] && !signs[i - 1, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 8 && !signs[i, j + 2] && !signs[i - 1, j + 1]) return true;
                       else return false;
                   }
                   
               case 37:
                   if (d == -1)
                   {
                       if (j != 1 && !signs[i, j - 2] && !signs[i + 1, j - 1] && !signs[i - 1, j - 1]) return true;
                       else return false;
                   }
                   else
                   {
                       if (j != 9 && !signs[i, j + 1] && !signs[i + 1, j + 1] && !signs[i - 1, j + 1]) return true;
                       else return false;
                   }

               default:
                   return false;
           }            
        }

這個函數檢查是否有填滿的"列",如果有將其刪除,並將剩餘的格點往下向一列,直到沒有可刪除的列:
 void full_line_check()
  {
            uint row_sum;
            uint i, j;

            i = 0;
            while(i < 20)
            {
                row_sum = 0;
                for (j = 0; j < 10; j++)
                    if (signs[i, j]) row_sum++;

                if (row_sum == 10)
                {
                    score += 20;
                    label_score.Text = "Score:" + score.ToString();
                    for (j = 0; j < 10; j++)
                        signs[i, j] = false;

                    show_grids(); // show a black line 

                    for (uint y = i; y < 21; y++)
                        for (j = 0; j < 10; j++)
                        {
                            signs[y, j] = signs[y + 1, j];
                            grids_color[y, j] = grids_color[y + 1, j];
                        }
                    show_grids();
                }
                else i++;
            }
        }

每次timer tick要做的事: 基本上就是檢查方塊是否遇到障礙物,如果沒有就往下降一格;如果方塊遇到障礙物就停止並檢查是否有可刪除的列,之後再降下新的方塊,最後就是顯示格點內的最新狀況。

 private void timer1_Tick(object sender, EventArgs e)
        {
            if (y_direction(block_type, block_row, block_col))
            {
                block_row_pre = block_row; block_row_pre = block_row; block_type_pre = block_type;
                block_row--;

                if (block_row == 19)
                {
                    block_type_next = (uint)rander.Next(0, 7) + 1;
                    display_next_block(block_type_next);
                    block_count++;
                    score += 5;
                    label_block_count.Text = "Blocks:" + block_count.ToString();
                    label_score.Text = "Score:" + score.ToString();
                    if (game_mode == 1)
                    {
                        timer_interval = 1010 - (int)(score / 150) * 50;
                        if (timer_interval <= 0)
                            timer_interval = 10;

                        timer1.Interval = timer_interval;
                        label_level.Text = "Level:" + (1010 - timer_interval) / 50;
                    }                    
                  }
                erase_block(block_row_pre, block_col_pre, block_type_pre);
                update_block(block_row, block_col, block_type);
                show_grids();
                block_row_pre = block_row;
                block_changed = false;
            }
            else 
            {             
                show_grids();
                full_line_check();
                if (block_row == 20)
                {                    
                  label_info.Text = "Game Over!";
                  button1.Visible = true;
                  button1.Enabled = true;
                  timer1.Enabled = false;
                  return;

                };
                block_type = block_type_next; 
                block_row = 20;
                block_col = 4;
                block_row_pre = 20;
                block_col_pre = 4;
                block_type_pre = block_type;
                block_changed = false;
            }
        }



另外,偵測鍵盤:

包括左右方向鍵(左右移動): 
        當方塊觸及左右邊界時,須停止移動。

下方向鍵(將方塊快速拉下): 當方塊遇到障礙物,須停止下降。

空白建(翻轉方塊): 
       根據方塊目前的型態並偵測是否可進行翻轉(空間是否足夠?),條件符合才進行翻轉,否則型態不變。

偵測按鍵,並做對應的動作:

       private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.P)
            {
                if (game_mode == 0) { game_mode = 1; timer1.Enabled = true; }
                else { game_mode = 0; timer1.Enabled = false; }
            }

            if (e.KeyCode == Keys.Left)
            {
                if (x_direction(block_type, block_row, block_col, -1))
                {
                    block_col_pre = block_col; block_col--;
                    block_changed = true;
                }
            }

            if (e.KeyCode == Keys.Right)
            {
                if (x_direction(block_type, block_row, block_col, 1))
                {
                    block_col_pre = block_col; block_col++;
                    block_changed = true;
                }
            }

            if (e.KeyCode == Keys.Space)
            {
                block_type_pre = block_type;
                block_col_pre = block_col; block_row_pre = block_row;
                block_type = next_block_type(block_type, block_row, block_col);
                if(block_type != block_type_pre)
                    block_changed = true;
            }

            if (e.KeyCode == Keys.S)
            {
                game_mode = 2;               
                timer_interval -= 50;
               
                if(timer_interval <= 0)
                    timer_interval = 1;
                
                timer1.Interval = timer_interval;
                label_level.Text = "Level:" + (1010 - timer_interval) / 50;
            }

            if (e.KeyCode == Keys.A)
            {
                game_mode = 2;
                timer_interval += 50;

                if (timer_interval >= 1010)
                    timer_interval = 1010;

                timer1.Interval = timer_interval;
                label_level.Text = "Level:" + (1010 - timer_interval) / 50;
            }

            if (e.KeyCode == Keys.Down)
                timer1.Interval = 15;
      
            if (block_changed)
            {
                erase_block(block_row_pre, block_col_pre, block_type_pre);
                update_block(block_row, block_col, block_type);
                show_grids();
                block_row_pre = block_row; block_col_pre = block_col; block_type_pre = block_type;
                block_changed = false;
            }
        }

檢查方塊是否可翻轉,並做對應的動作:

        uint next_block_type(uint type, uint i, uint j)
        {
            switch(type)
            {
                case 1:
                    if (j <= 7 && j>=1 && !signs[i+2, j-1] && !signs[i+2, j + 1] && !signs[i+2, j + 2])
                    {
                        block_row = i + 2; block_col = j - 1;
                        return 11;
                    }
                    else return 1;
                
                case 11:
                    if (i >= 2 && !signs[i - 1, j+1] && !signs[i - 2, j+1] && !signs[i +1, j+1])
                    {
                        block_row = i -2; block_col = j + 1;
                        return 1;
                    }
                    else return 11; 
                
                case 2: return 2; 
                
                case 3:
                    if (i >= 1 && !signs[i + 1, j+1] && !signs[i-1, j])
                        return 13;
                    else return 3;  

                case 13:
                    if (j >= 1 && !signs[i + 1, j] && !signs[i+1, j-1])
                        return 3;
                    else return 13;  
                
                case 4:
                    if (i >= 1 && !signs[i, j+1] && !signs[i-1, j+1])
                        return 14;
                    else return 4;  

                case 14:
                    if (j >= 1 && !signs[i, j-1] && !signs[i + 1, j + 1])
                        return 4;
                    else return 14;   

                case 5:
                    if (!signs[i + 2, j] && !signs[i, j + 1])
                    {
                        block_col = j + 1;
                        return 15;
                    }
                    else return 5;   

                case 15:
                    if (j >= 2 && !signs[i, j-2] && !signs[i + 1, j] )
                    {
                        block_row = i + 1;
                        return 25;
                    }
                    else return 15;                       

                case 25:
                    if (i >= 2 && !signs[i, j - 1] && !signs[i - 2, j])
                    {
                        block_col = j - 1;
                        return 35;
                    }
                    else return 25;  

                case 35:
                    if (j <= 7 && !signs[i - 1, j] && !signs[i, j + 2])
                    {
                        block_row = i - 1;
                        return 5;
                    }
                    else return 35; 

                case 6:
                    if (!signs[i, j - 1] && !signs[i + 2, j] )
                    {
                        block_col = j - 1;
                        return 16;
                    }
                    else return 6; 

                case 16:
                    if (j <= 7 && !signs[i - 1, j] && !signs[i, j + 2])
                    {
                        block_row = i + 1;
                        return 26;
                    }
                    else return 16; 

                case 26:
                    if (i >= 2 && !signs[i, j +1] && !signs[i - 2, j])
                    {
                        block_col = j + 1;
                        return 36;
                    }
                    else return 26; 

                case 36:
                    if (j >= 2 && !signs[i, j-2] && !signs[i - 1, j])
                    {
                        block_row = i - 1;
                        return 6;
                    }
                    else return 36; 

                case 7:
                    if (i>=1 && !signs[i-1, j])
                        return 17;
                    else return 7;  

                case 17:
                    if (j >= 1 && !signs[i, j-1])
                        return 27;
                    else return 17;  

                case 27:
                    if (!signs[i+1, j])
                        return 37;
                    else return 27;  

                case 37:
                    if (j<=8 && !signs[i, j+1])
                        return 7;
                    else return 37;  

                default: return 0;  
            }
        }


程式的邏輯大概如上所述,其他則為旁枝末節,如果還是有疑問,請直接查看完整程式碼。附上整個Visual Studio 的專案,直接打開就可編譯並執行。
如有發現Bug或有任何建議,請不吝賜教,感謝囉。

2 則留言:

  1. 不好意思想請教您一下,我現在有三個tabpage,然後我想讓您的俄羅斯方塊在第三個tabpage上呈現出來,但我發現用程式拉出的200個黑色方格那邊,會被壓在tabpage下而顯示不出來,想請問一下該如何修改呢?

    回覆刪除
    回覆
    1. 嗨,你好,如果你要在第三個page呈現這200個label的話,應該把
      this.Controls.Add(grids[i, j]);這行程式改成
      tabPage3.Controls.Add(grids[i, j]);
      這樣才能真的把labels加到你要的分頁,試試看。Good Luck!

      刪除