手把手教你用 Excel 編寫(xiě)俄羅斯方塊

編碼珠璣 2022/11/30 13:38:11 責(zé)編:遠(yuǎn)生

看到這個(gè)題目,想必你一定會(huì)感到非常驚訝,什么,Excel 居然能開(kāi)發(fā)游戲?沒(méi)錯(cuò),Excel 的強(qiáng)大取決于使用者,遇強(qiáng)則強(qiáng),遇弱則弱。但我這篇文章并不是為了展示 Excel 使用過(guò)程中的奇技淫巧,而是主要寫(xiě)給那些準(zhǔn)備學(xué)習(xí)編程但又沒(méi)什么計(jì)算機(jī)基礎(chǔ)的那些人,或者對(duì) Excel 感興趣的那些人。

對(duì)于那些正在學(xué)習(xí)編程的人,尤其是那些從其他領(lǐng)域跨入這個(gè)行業(yè)的人,興趣才是最大的動(dòng)力。我從事計(jì)算機(jī)編程這么長(zhǎng)時(shí)間,感覺(jué)編程是一件非常有意義的事情。然而我卻我經(jīng)常聽(tīng)到有些人,尤其是那些在校學(xué)生們抱怨說(shuō)編程學(xué)起來(lái)太枯燥了,堅(jiān)持不下去。我覺(jué)得這部分人一方面是方向錯(cuò)了,另一方面就是在實(shí)際學(xué)習(xí)過(guò)程中對(duì)自己做出成果沒(méi)有任何的成就感,而后者,往往占據(jù)了重要原因。

我認(rèn)為,對(duì)于編程的初學(xué)者,選擇第一門(mén)語(yǔ)言應(yīng)該具備下面兩個(gè)特點(diǎn):

1),盡可能簡(jiǎn)單,盡量少與底層硬件(諸如內(nèi)存管理等)相關(guān)聯(lián),調(diào)試方便,IDE 界面簡(jiǎn)單;

2),功能相對(duì)強(qiáng)大,能開(kāi)發(fā)各種小插件工具;

就目前行業(yè)內(nèi)比較常用的編程語(yǔ)言中,能夠同時(shí)滿(mǎn)足上述兩個(gè)特點(diǎn)的也就數(shù) Python,office for VBA,Java 了,然而,Python 雖然簡(jiǎn)單功能又強(qiáng)大,但是需要配置環(huán)境,而且要安裝臃腫的 IDE,這些對(duì)于初學(xué)者來(lái)說(shuō),無(wú)形之中又增加了學(xué)習(xí)成本,更別說(shuō) Java 了,所以剩下的就數(shù) VBA (Visual Basic for Application) 了。VBA 屬于 visual basic 語(yǔ)言的子集,除了繼承了部分 vb 功能外,還特意針對(duì)一些軟件做了接口封裝,使用方便。有人說(shuō) VBA 語(yǔ)法太隨意,對(duì)于初學(xué)者不是件好事,如果學(xué) C 的話(huà),將來(lái)學(xué) C++ 就簡(jiǎn)單很多了。我不同意這種觀(guān)點(diǎn),對(duì)于前者,仁者見(jiàn)仁,但后者就是在扯淡,因?yàn)?C++ 是一門(mén)極其復(fù)雜的編程語(yǔ)言,除了繼承了 C 的繁瑣指針以外,還衍生出了諸如多重繼承、類(lèi)模板、智能指針等恐怖級(jí)別的編程范式,所以說(shuō),對(duì)于初學(xué)者,我不建議直接就去學(xué) C++.

為什么選擇 VBA 作為初學(xué)者的語(yǔ)言呢,因?yàn)樗藵M(mǎn)足上面所說(shuō)的兩個(gè)特點(diǎn)外,還有一些其他的優(yōu)點(diǎn),諸如:

1),使用簡(jiǎn)單:不需要安裝開(kāi)發(fā)工具,更不需要配環(huán)境、安裝語(yǔ)言包,只要你電腦里面有 office 軟件即可。

2),用途廣泛:幾乎所有的工程軟件、辦公軟件都支持用 VBA 做二次開(kāi)發(fā),例如財(cái)務(wù)人員如果發(fā)現(xiàn) Excel 自帶的公式有局限性的話(huà),完全可以自己用 VBA 開(kāi)發(fā)自己需要的控件;機(jī)械設(shè)計(jì)人員如果學(xué)了 VBA 后可以開(kāi)發(fā)一些自己需要的代碼塊,極大程度地提高自己 CAD 的繪圖速度。很難想象,Excel 的重度用戶(hù)尤其是財(cái)務(wù)人員不懂 VBA 的話(huà)他的工作量有多可怕。

3),調(diào)試簡(jiǎn)單方便。

所以,這次我也選擇 VBA 作為這次編寫(xiě) Demo 的語(yǔ)言,為了照顧更多的初學(xué)者,我將每一步的細(xì)節(jié)都盡可能地呈現(xiàn)出來(lái),由于每個(gè) Excel 版本不一樣,我電腦用的是 2010 版的,所以,我就用 2010 版進(jìn)行說(shuō)明,其他版本也一樣,只是界面可能稍有區(qū)別。我相信,只要親手按照我的方法做出這個(gè)游戲,除了你將認(rèn)識(shí)到 Excel 的強(qiáng)大之處外,你也將逐步體會(huì)到編程的樂(lè)趣。鑒于時(shí)間所限,內(nèi)容可能有部分疏忽之處,還望大家提出改正。

下面是正文:

首先看一下游戲最終大致的效果圖:

首先我們思考一下俄羅斯方塊游戲的大致架構(gòu):

1),初始化界面:創(chuàng)建方塊所需要的地圖。

2),隨機(jī)生成俄羅斯方塊:俄羅斯方塊總共有 7 種形態(tài),每種形態(tài)均有 4 個(gè)框格組成,每種方塊各對(duì)應(yīng)一種顏色。可以創(chuàng)建一個(gè)數(shù)組存儲(chǔ)每種方塊的坐標(biāo),再用另外一個(gè)數(shù)組存儲(chǔ)方塊的對(duì)應(yīng)的顏色。

3),移動(dòng)旋轉(zhuǎn)方塊:分為向左,向右,向下。擦拭完后重新繪制,產(chǎn)生移動(dòng)旋轉(zhuǎn)的效果。

4),沒(méi)產(chǎn)生新的方塊,都進(jìn)行一定速度的下落,一旦碰到障礙物,不能下落,再生成新的方塊。

5),不斷掃描是否有任何一行填滿(mǎn),如果為真,則本行刪除,上面下落。每行積分為 10 分。

首先創(chuàng)建一個(gè) Excel 文件,隨意命名。打開(kāi)后,由于 office 默認(rèn)隱藏了開(kāi)發(fā)工具狀態(tài)欄,所以我們需要在 Excel 選項(xiàng) > 自定義功能區(qū)將其調(diào)出來(lái),將其勾選后確認(rèn):

隨后,我們發(fā)現(xiàn)主界面多了開(kāi)發(fā)工具的選項(xiàng):

我們?cè)僭?Sheet1 表格里面將 A~K 列的列寬大致調(diào)成跟行高一樣,讓它大致稱(chēng)為一個(gè)正方形的區(qū)域:

我們點(diǎn)擊 Visual Basic 菜單,打開(kāi)編寫(xiě)代碼界面,我們插入首先插入一個(gè)代碼模塊,用于編寫(xiě)我們自己的代碼:

由于方塊有 7 中形狀,為了讓程序繪制方便,我用一個(gè)三維數(shù)組存儲(chǔ)所有形狀的坐標(biāo),每種形狀都有一個(gè)中心坐標(biāo) (0,0),其余三個(gè)方框的坐標(biāo)按照中心坐標(biāo)來(lái)計(jì)算相對(duì)坐標(biāo),例如丁字形狀的方塊:

如果中心的坐標(biāo)為 (0,0) 的話(huà),剩余三個(gè)從右到左逆時(shí)針三個(gè)坐標(biāo)分別為 (0,1),(-1,0),(0,-1),之所以將垂直方向作為 X 軸是因?yàn)?Excel 坐標(biāo)的固有屬性,例如 Cells (1,2) 代表第一行第二列個(gè)單元格。每個(gè)方塊的對(duì)象有中心坐標(biāo),顏色,形狀等屬性,所以我們需要定義幾個(gè)模塊變量,代碼如下:

Option Explicit

Dim MySheet As Worksheet
Dim iCenterRow As Integer   '方塊中心行
Dim iCenterCol As Integer   '方塊中心列
Dim ColorArr()              '7種顏色
Dim ShapeArr()              '7種方塊
Dim iColorIndex As Integer  '顏色索引
Dim MyBlock(4, 2) As Integer    '每個(gè)方框的坐標(biāo)數(shù)組,會(huì)隨著方塊的移動(dòng)而變化
Dim bIsObjectEnd As Boolean     '本個(gè)方塊是否下降到最低點(diǎn)
Dim iScore As Integer       '分?jǐn)?shù)

考慮到每種方塊坐標(biāo)的不一樣,所以我采用一個(gè)三維數(shù)組來(lái)存儲(chǔ)方塊坐標(biāo),為了方便,我采用 VBA 自帶的接口 Array () 函數(shù)給自己的 ShapeArr () 賦值。同時(shí)要在主界面上顯示出玩家的分?jǐn)?shù),所以這兩個(gè)功能我們作為一個(gè)初始化函數(shù),我們定義一個(gè) Init () 子過(guò)程,代碼如下:

'初始化 By@yaxi_li
uPrivate Sub Init()
    Set MySheet = Sheets("Sheet1")
    ColorArr = Array(3, 4, 5, 6, 7, 8, 9)    
    ShapeArr = Array(Array(Array(0, 0), Array(0, 1), Array(0, -1), Array(0, 2)), _       
                 Array(Array(0, 0), Array(0, 1), Array(0, -1), Array(-1, -1)), _                 
                 Array(Array(0, 0), Array(0, 1), Array(0, -1), Array(-1, 1)), _                 
                 Array(Array(0, 0), Array(-1, 1), Array(-1, 0), Array(0, 1)), _                 
                 Array(Array(0, 0), Array(0, -1), Array(-1, 0), Array(-1, 1)), _                 
                 Array(Array(0, 0), Array(0, 1), Array(-1, 0), Array(-1, -1)), _                 
                 Array(Array(0, 0), Array(0, 1), Array(0, -1), Array(-1, 0)))
                 
    With MySheet.Range("B1:K20")        
        .Interior.Pattern = xlNone        
        .Borders.LineStyle = xlNone
    
        .Borders(xlEdgeBottom).Weight = xlMedium        
        .Borders(xlEdgeRight).Weight = xlMedium        
        .Borders(xlEdgeLeft).Weight = xlMedium    
    End With
    '設(shè)定長(zhǎng)寬比例    
    MySheet.Columns("A:L").ColumnWidth = 2    
    MySheet.Rows("1:30").RowHeight = 13.5
    
    iScore = 0    
    MySheet.Range("N1").Value = "分?jǐn)?shù)"    
    MySheet.Range("O1").Value = iScore
End Sub

這時(shí)候,我們初始化變量與功能的函數(shù)基本上實(shí)現(xiàn)了。下一步我們要編寫(xiě)生成一個(gè)新方塊的函數(shù),為了實(shí)現(xiàn)程序的模塊化,低耦合,我們將本功能封裝成一個(gè)獨(dú)立的函數(shù)。

由于繪制函數(shù) DrawBlock () 需要根據(jù)傳遞過(guò)來(lái)的做標(biāo)數(shù)組來(lái)進(jìn)行繪制,同時(shí)我們需要知道這個(gè)方塊的中心坐標(biāo)在哪里,還有對(duì)應(yīng)的顏色,所以我們需要傳遞 4 個(gè)參數(shù),其中數(shù)組需要傳址 (ByRef),代碼如下:

'繪制方塊,By@yaxi_liu
Private Sub DrawBlock(ByVal center_row As Integer, ByVal center_col As Integer, ByRef block() As Integer, ByVal icolor As Integer)
    Dim Row As Integer, Col As Integer    
    Dim i As Integer    
    For i = 0 To 3 
        Row = center_row + block(i, 0)        
        Col = center_col + block(i, 1)        
        MySheet.Cells(Row, Col).Interior.ColorIndex = icolor  '顏色索引        
        MySheet.Cells(Row, Col).Borders.LineStyle = xlContinuous    '周?chē)油饪蚓€(xiàn)    
    Next
End Sub

至此,繪制函數(shù)已經(jīng)完成,為了防止 Bug 出現(xiàn),我們需要測(cè)試一下,我們?cè)俣x一個(gè)入口函數(shù),Start (), 同時(shí)定義一個(gè)臨時(shí)方塊數(shù)組,調(diào)用 DrawBlock () 進(jìn)行測(cè)試。在主界面添加一個(gè)按鈕,將其指定到 Start 函數(shù),并將其拖入合適的位置:

Start 函數(shù)代碼如下:

Sub Start()
    Call Init
    
    iCenterRow = 5    
    iCenterCol = 6    
    iColorIndex = 4    
    Dim i As Integer    
    For i = 0 To 3   
        MyBlock(i, 0) = ShapeArr(iColorIndex)(i)(0)        
        MyBlock(i, 1) = ShapeArr(iColorIndex)(i)(1)
    Next    
    Call DrawBlock(iCenterRow, iCenterCol, MyBlock, ColorArr(iColorIndex))
    End Sub

我們運(yùn)行一下,看看效果:

好,測(cè)試結(jié)果顯示完全沒(méi)問(wèn)題。

由于后期我們需要在表格最上方的固定位置不斷隨機(jī)生成新的方塊,所以我們應(yīng)該將此功能再次封裝為一個(gè)獨(dú)立函數(shù),為了防止產(chǎn)生偽隨機(jī)數(shù),我們采用 Timer 作為當(dāng)前種子,隨機(jī)生成 0~6 之間的數(shù)組,每個(gè)對(duì)應(yīng)形狀數(shù)組與顏色數(shù)組的索引,代碼如下:

'隨機(jī)生成新的方塊函數(shù) By@yaxi_liu
Private Sub GetBlock()
    Randomize (Timer)    
    Dim i As Integer    
    iColorIndex = Int(7 * Rnd)    
    iCenterRow = 2    
    iCenterCol = 6
    
    For i = 0 To 3        
        MyBlock(i, 0) = ShapeArr(iColorIndex)(i)(0)        
        MyBlock(i, 1) = ShapeArr(iColorIndex)(i)(1)    
    Next    
    Call DrawBlock(iCenterRow, iCenterCol, MyBlock, ColorArr(iColorIndex))
End Sub

既然生成了方塊,我們就要讓方塊能夠左右下移動(dòng),分為三個(gè)方向。移動(dòng)的方法是首先擦除掉當(dāng)前的方塊,再根據(jù)規(guī)定的移動(dòng)方向,計(jì)算新的坐標(biāo),再根據(jù)新的坐標(biāo)重新繪制,這樣就產(chǎn)生了移動(dòng)的現(xiàn)象。但是,在移動(dòng)之前,我們需要判斷是否可以移動(dòng)。

首先,我們需要編寫(xiě)判斷是否能夠移動(dòng)或者旋轉(zhuǎn)的函數(shù) CanMoveRotate,此函數(shù)很簡(jiǎn)單,也就是將移動(dòng)后或者旋轉(zhuǎn)后的坐標(biāo)傳遞過(guò)來(lái),判斷是否越界,或者當(dāng)前位置上是否有其他顏色即可,代碼如下:

'是否能夠移動(dòng)或者旋轉(zhuǎn)函數(shù),By@yaxi_liu
Private Function CanMoveRotate(ByVal center_row As Integer, ByVal center_col As Integer, ByRef block() As Integer) As Boolean    
    '本函數(shù)形參均為變換后的坐標(biāo)
    '首先判斷是否越界    
    Dim Row As Integer, Col As Integer    
    Dim i As Integer    
    CanMoveRotate = True    
    For i = 0 To 3    
        Row = center_row + block(i, 0)        
        Col = center_col + block(i, 1)        
        If Row > 20 Or Row < 0 Or Col > 11 Or Col < 2 Then      '越界            
           CanMoveRotate = False        
        End If        
        If MySheet.Cells(Row, Col).Interior.Pattern <> xlNone Then  '只要有一個(gè)顏色,則為阻擋            
           CanMoveRotate = False        
        End If    
    Next
End Function

我們還需要一個(gè)擦除當(dāng)前方塊的函數(shù) EraseBlock,根據(jù)傳遞過(guò)來(lái)的坐標(biāo)直接擦拭掉,代碼如下:

'擦除方塊 By@yaxi_liu
Private Sub EraseBlock(ByVal center_row As Integer, ByVal center_col As Integer, ByRef block() As Integer)
    Dim Row As Integer, Col As Integer    
    Dim i As Integer    
    For i = 0 To 3        
        Row = center_row + block(i, 0)        
        Col = center_col + block(i, 1)        
        MySheet.Cells(Row, Col).Interior.Pattern = xlNone        
        MySheet.Cells(Row, Col).Borders.LineStyle = xlNone    
     Next
 End Sub

我們?cè)倬帉?xiě)移動(dòng)方塊的函數(shù) MoveBlock,我們規(guī)定,形參 direction 代表方向,-1 代表向左,0 代表向下,1 代表向右,注意移動(dòng)后需要保存當(dāng)前坐標(biāo)。新增形參 direction,代碼如下:

'移動(dòng)方塊 By@yaxi_liu
Private Sub MoveBlock(ByVal center_row As Integer, ByVal center_col As Integer, ByRef block() As Integer, ByVal icolor As Integer, ByVal direction As Integer)    
    Dim Row As Integer, Col As Integer    
    Dim i As Integer    
    Dim old_row As Integer, old_col As Integer  '保存最早的中心坐標(biāo)    
    old_row = center_row    
    old_col = center_col
    
    '首先擦除掉原來(lái)位置的    
    Call EraseBlock(center_row, center_col, block)
    
    '-1 代表向左,1 代表向右,0 代表鄉(xiāng)下    
    Select Case direction    
        Case Is = -1      
            center_col = center_col - 1        
        Case Is = 1        
            center_col = center_col + 1        
        Case Is = 0        
            center_row = center_row + 1    
    End Select
    '再繪制    
    If CanMoveRotate(center_row, center_col, block) Then      
        Call DrawBlock(center_row, center_col, block, icolor)        
        '保存中心坐標(biāo)        
        iCenterRow = center_row        
        iCenterCol = center_col    
    Else        
        Call DrawBlock(old_row, old_col, block, icolor)        
        '保存中心坐標(biāo)        
        iCenterRow = old_row        
        iCenterCol = old_col        
        If direction = 0 Then         
           bIsObjectEnd = True        
       End If    
   End If
    '保存方塊坐標(biāo)    
    For i = 0 To 3        
       MyBlock(i, 0) = block(i, 0)        
       MyBlock(i, 1) = block(i, 1)    
   Next
   
End Sub

移動(dòng)方塊實(shí)現(xiàn)后,我們?cè)賮?lái)編寫(xiě)旋轉(zhuǎn)方塊函數(shù) RotateBlock,這里我們統(tǒng)一規(guī)定為逆時(shí)針旋轉(zhuǎn)。跟移動(dòng)函數(shù)一樣,方法也是先擦除掉舊坐標(biāo)的后,再根據(jù)新坐標(biāo)繪制出新的方塊。只不過(guò)旋轉(zhuǎn)稍微麻煩一點(diǎn)。

不難計(jì)算出,假如一個(gè)向量 (x,y) 在逆時(shí)針旋轉(zhuǎn) 90 度后的坐標(biāo)為 (-y,x).根據(jù)這個(gè)公式,編寫(xiě)旋轉(zhuǎn)函數(shù)。但是注意事先應(yīng)該先判斷是否達(dá)到旋轉(zhuǎn)的條件。代碼如下:

'旋轉(zhuǎn)方塊函數(shù) By@yaxi_liu
Private Sub RotateBlock(ByVal center_row As Integer, ByVal center_col As Integer, ByRef block() As Integer, ByVal icolor As Integer)    
     Dim i As Integer    
     '先擦除原來(lái)的    
     Call EraseBlock(center_row, center_col, block)    
     Dim tempArr(4, 2) As Integer    
     '保存數(shù)組    
     For i = 0 To 3      
         tempArr(i, 0) = block(i, 0)        
         tempArr(i, 1) = block(i, 1)    
     Next    
     '旋轉(zhuǎn)后的坐標(biāo)重新賦值    
     For i = 0 To 3     
         block(i, 0) = -tempArr(i, 1)        
         block(i, 1) = tempArr(i, 0)    
     Next i
     
    '重新繪制新的方塊    
    If CanMoveRotate(center_row, center_col, block) Then        
        Call DrawBlock(center_row, center_col, block, icolor)        
        '保存方塊坐標(biāo)        
        For i = 0 To 3          
            MyBlock(i, 0) = block(i, 0)            
            MyBlock(i, 1) = block(i, 1)        
        Next    
    Else      
        Call DrawBlock(center_row, center_col, tempArr, icolor)        
        '保存方塊坐標(biāo)        
        For i = 0 To 3         
            MyBlock(i, 0) = tempArr(i, 0)            
            MyBlock(i, 1) = tempArr(i, 1)        
        Next    
    End If
    '保存中心坐標(biāo)    
    iCenterRow = center_row    
    iCenterCol = center_col
    
End Sub

這時(shí)候,旋轉(zhuǎn)、移動(dòng)函數(shù)均已編寫(xiě)完畢。為了能夠讓游戲相應(yīng)鍵盤(pán)事件,我們需要在對(duì)應(yīng)的工作表代碼層添加事件函數(shù),注意這里我們需要調(diào)用 Windows API。我們規(guī)定鍵盤(pán)的左鍵為方塊向左 MoveObject (-1),右鍵為方塊向右 MoveObject (1),下鍵為方塊向下 MoveObject (0),上鍵為方塊旋轉(zhuǎn) RotateObject ()。我們?cè)?Sheet1 工作表里面編寫(xiě)如下 WorkSheet 事件代碼:

'鍵盤(pán)事件代碼,By@yaxi_liu
#If VBA7 And Win64 Then  
  Private Declare PtrSafe Function GetKeyboardState Lib "user32" (pbKeyState As Byte) As Long
#Else  
  Private Declare Function GetKeyboardState Lib "user32" (pbKeyState As Byte) As Long
#End If
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Dim keycode(0 To 255) As Byte    
    GetKeyboardState keycode(0)    
    If keycode(38) > 127 Then   '上     
        Call RotateObject    
    ElseIf keycode(39) > 127 Then  '右     
       Call MoveObject(1)    
    ElseIf keycode(40) > 127 Then '下     
       Call MoveObject(0)    
    ElseIf keycode(37) > 127 Then '左     
       Call MoveObject(-1)    
   End If
End Sub

由于我們自己定義的 MoveBlock 與 RotateBlock 包類(lèi)對(duì)象的形參,因此事件響應(yīng)中不能直接調(diào)用。在這里我們將用兩個(gè) Public 的 MoveObject 與 RotateObject 函數(shù)在類(lèi)模塊里面再次封裝,方便事件調(diào)用,代碼如下:

'移動(dòng)對(duì)象 By@yaxi_liu
Public Sub MoveObject(ByVal dir As Integer)
    Call MoveBlock(iCenterRow, iCenterCol, MyBlock, ColorArr(iColorIndex), dir)
End Sub
'旋轉(zhuǎn)對(duì)象 By@yaxi_liu
Public Sub RotateObject()
    Call RotateBlock(iCenterRow, iCenterCol, MyBlock, ColorArr(iColorIndex))
End Sub

至此,方塊功能方面已經(jīng)完全實(shí)現(xiàn),我們隨機(jī)生成一個(gè)進(jìn)行測(cè)試:

為了方便,我們將按鈕 1 里面的文字更改成“啟動(dòng)游戲四個(gè)字”:

隨后,開(kāi)始編寫(xiě)程序自動(dòng)運(yùn)行的代碼。由于俄羅斯方塊是生成方塊后,按照一定的速度進(jìn)行下降,一旦碰到障礙物后本方塊結(jié)束,再生成新的方塊,如此循環(huán)。由于 VBA 不支持定時(shí)器,所以我們采用 while (true) 循環(huán)的方法進(jìn)行不斷生成方塊。為了避免 CPU 資源過(guò)度占用,我們?cè)谘h(huán)之間加入延時(shí)函數(shù),供循環(huán)調(diào)用,代碼如下:

'延時(shí)函數(shù) By@yaxi_liu
Private Sub delay(T As Single)  
    Dim T1 As Single    
    T1 = Timer    
    Do     
       DoEvents    
    Loop While Timer - T1 < T
End Sub

在下降過(guò)程中,我們需要知道是否某一行已經(jīng)滿(mǎn)了,判斷的方法很簡(jiǎn)單,查詢(xún)整行是否全部涂色即可。如果滿(mǎn)了,我們刪除本行,同時(shí)將第一行到本行下降填充。同時(shí)更新分?jǐn)?shù)。因此我們?cè)僖胍粋€(gè)函數(shù) DeleteFullRow,代碼如下:

'消除滿(mǎn)行函數(shù) By@yaxi_liu
Private Sub DeleteFullRow()    
    Dim i As Integer, j As Integer    
    For i = 1 To 20    
        For j = 2 To 11          
            If MySheet.Cells(i, j).Interior.ColorIndex < 0 Then             
                Exit For            
            ElseIf j = 11 Then                
                MySheet.Range(Cells(1, 2), Cells(i - 1, j)).Cut Destination:=MySheet.Range(Cells(2, 2), Cells(i, j))       'Range("B2:K18")                
                iScore = iScore + 10            
            End If        
        Next j    
    Next i    
    MySheet.Range("N1").Value = "分?jǐn)?shù)"    
    MySheet.Range("O1").Value = iScore
End Sub

再在 Start () 函數(shù)里面添加 while 循環(huán),上面兩個(gè)函數(shù)一樣添加進(jìn)去代碼如下:

'啟動(dòng)函數(shù) By@yaxi_liu
Sub Start()
    Call Init    
    While (True)       
        Call GetBlock        
        bIsObjectEnd = False    '本方塊對(duì)象是否結(jié)束
        
        While (bIsObjectEnd = False)          
           Call delay(0.5)            
           Call MoveBlock(iCenterRow, iCenterCol, MyBlock, ColorArr(iColorIndex), 0)            
           MySheet.Range("L21").Select            
           With MySheet.Range("B1:K20")               
               .Borders(xlEdgeBottom).Weight = xlMedium                
               .Borders(xlEdgeRight).Weight = xlMedium                
               .Borders(xlEdgeLeft).Weight = xlMedium            
            End With        
         Wend        
         Call DeleteFullRow    
     Wend
 End Sub

到這里,本游戲的編寫(xiě)就算徹底結(jié)束了,點(diǎn)擊 Sheet1 界面上面的“按鈕 1”按鈕即可開(kāi)始游戲。我們?cè)僭囃嬉幌?,向左鍵代表向左,右鍵代表向右,上鍵代表旋轉(zhuǎn),下鍵代表下降。看一下效果:

哈哈,試玩結(jié)束沒(méi)問(wèn)題,非常完美,過(guò)程雖然長(zhǎng)久,但值得你細(xì)細(xì)研究,也希望你能從中夠體會(huì)到編程的樂(lè)趣。如果您覺(jué)得學(xué)到了知識(shí),希望您將這篇文章分享給更多的人,謝謝!

如果你想要源代碼文件,請(qǐng)?jiān)谖恼麻_(kāi)頭部分點(diǎn)擊我的名字關(guān)注我的公眾號(hào),在對(duì)話(huà)欄里面回復(fù)“俄羅斯方塊”五個(gè)字即可,我會(huì)將源代碼以及文件都發(fā)送給你,方便你后期研究代碼學(xué)習(xí)。

本文來(lái)自微信公眾號(hào):編碼珠璣 (ID:gh_f65e0111d17a),作者:劉亞曦

廣告聲明:文內(nèi)含有的對(duì)外跳轉(zhuǎn)鏈接(包括不限于超鏈接、二維碼、口令等形式),用于傳遞更多信息,節(jié)省甄選時(shí)間,結(jié)果僅供參考,IT之家所有文章均包含本聲明。

相關(guān)文章

關(guān)鍵詞:代碼Excel

軟媒旗下網(wǎng)站: IT之家 最會(huì)買(mǎi) - 返利返現(xiàn)優(yōu)惠券 iPhone之家 Win7之家 Win10之家 Win11之家

軟媒旗下軟件: 軟媒手機(jī)APP應(yīng)用 魔方 最會(huì)買(mǎi) 要知