最近突然有個想法,想用VBA做一個貪食蛇的小遊戲,歷經了5天終於把它完成了,製作的過程中,遇到了一些問題,這些問題我們一一的解決它,完成了一個很陽春的貪食蛇,雖然沒有很多附加功能,但也算是個小成果,在這邊分享我的作法給大家。
我們將貪食蛇所需要的功能解構,再將每一個部分建立好,最後拼起來變成一個完整的遊戲,我們將其解構如下:
1.
建立遊戲框架
2.
初始蛇身
3.
隨機產生食物
4.
讓蛇身移動
5.
用鍵盤操控方向
6.
死掉的條件
7.
蛇身移動的速度
8.
吃到食物蛇身變長
我們針對每一個部分進行說明:
1.
建立遊戲框架
我們用很陽春的方式,建立一個30*30的範圍,讓蛇只能在這範圍內移動。
2.
初始蛇身
我們的初始蛇身設定成長度為4,亦可自訂,將蛇頭的部分定位在(15,15)的位置(也就是P16),然後讓蛇一開始往上走,所以蛇身會是(15,15)、(15,16)、(15,17),(15,18),然後將此四格填黑,形成初始的蛇身。
程式碼:
Dim startpoi_x%, startpoi_y%
Cells.Interior.ColorIndex = 0
startpoi_x = 15: startpoi_y = 15: length = 4: flag = False
ReDim body_x(length - 1): ReDim body_y(length - 1)
For e = 0 To length - 1
body_x(e) = startpoi_x + e: body_y(e) = startpoi_y
Range("A1").Offset(body_x(e),
body_y(e)).Interior.Color = vbBlack
Next e
3. 隨機產生食物
我們將隨機產生食物的功能寫成另一個Sub,需要產生食物,就呼叫此函數。我們利用隨機產生兩個1~30的整數,分別為列跟行,再針對這個位置將格子填黑,形成隨機產生食物的效果。
程式碼:
Call Randfood
Sub Randfood()
Dim Max%, Min%
Dim flag_generate As Boolean
Max = 30: Min = 1
While Not flag_generate
RandNum_x = Int((Max - Min + 1) * Rnd() + Min)
RandNum_y = Int((Max - Min + 1) * Rnd() + Min)
If IsError(Application.Match(RandNum_x, body_x, 0)) Or
IsError(Application.Match(RandNum_y, body_y, 0)) Then flag_generate = True
Wend
Range("A1").Offset(RandNum_x, RandNum_y).Interior.Color =
vbBlack
End Sub
4.
讓蛇身移動
讓蛇身移動的邏輯很簡單,就是將原本的蛇身最後一個身體反白,新的蛇頭填黑,這樣就可以形成蛇身移動的效果。但這邊遇到一個問題,下一個蛇頭如何決定? 所以我們寫個一個函數是更新蛇身的函數,這個函數會給出新的蛇身,根據新的蛇身就可以知道新的蛇頭。
程式碼:
Range("A1").Offset(body_x(length - 1), body_y(length -
1)).Interior.Color = vbWhite
body_x = movebody(movepoi_x, body_x,
length): body_y = movebody(movepoi_y, body_y, length)
Range("A1").Offset(body_x(0),
body_y(0)).Interior.Color = vbBlack
Function
movebody(headpoi As Integer, oldbody As Variant, bodylen As Integer) As Variant
Dim newbody() As Variant
ReDim newbody(bodylen - 1)
newbody(0) = headpoi
For nb = 0 To bodylen - 2
newbody(nb + 1) = oldbody(nb)
Next
movebody = newbody
End Function
5.
用鍵盤操控方向
要在蛇移動過程中操作鍵盤等同於在程式執行過程中控制鍵盤,這必須在城市中加上Doevents,讓程式執行中可以將控制權轉給作業系統,這時就可以操作鍵盤,另外我們還需要知道我們按下哪個鍵,所以我們在一開始用程式最上層宣告Private Declare PtrSafe
Function GetKeyboardState Lib "user32" (pbKeyState As Byte) As Long,並寫一個函數輸出0(上),1(下),2(左),3(右),就由輸出值我們知道按下了哪個方向,再呼叫movebody將蛇身更新,此時就可以達到操作蛇身的效果。
程式碼:
While Not flag
Range("A1").Select
Select Case dir
Case 0
j = j - 1
Case 1
j = j + 1
Case 2
i = i - 1
Case 3
i = i + 1
End Select
movepoi_x = startpoi_x + j: movepoi_y = startpoi_y + i ‘新的蛇頭
Sub keyboard_dir()
Dim
keys(0 To 255) As Byte
GetKeyboardState
keys(0)
Select
Case dir
Case 0, 1
If keys(37) > 127 Then dir = 2 '左
If keys(39) > 127 Then dir = 3 '右
Case 2, 3
If keys(38) > 127 Then dir = 0 '上
If keys(40) > 127 Then dir = 1 '下
End
Select
End Sub
6.
死掉的條件
死掉的條件有兩種,第一種撞到自己身體死掉 ; 第二種撞到牆死掉,第一種只要確定新的蛇頭是不是身體的一部分,是的話就等於撞到身體了。第二種只要判斷蛇頭位置有沒有超過邊界就好。
程式碼:
For m = 0 To length - 1
If movepoi_x = body_x(m) And movepoi_y
= body_y(m) Then MsgBox "Game Over": End
Next
If movepoi_x > 30 Or movepoi_x < 1 Or movepoi_y > 30 Or movepoi_y < 1 Then MsgBox "Game Over": End
7.
蛇身移動的速度
我們用了系統延遲的功能,讓蛇有在移動的效果,如果沒用延遲功能,程式的執行速度很快,會一下子就撞到牆壁,就Game Over了。所以我們在程式最上層宣告了Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr),並在程式中加了Sleep(80),其中80是指80毫秒的意思,亦可自訂,值越小速度越快。
8.
吃到食物蛇身變長
新的蛇頭的位置等於食物的位置等同於吃到食物了,此時將蛇身邊長一格,這邊用ReDim Preserve語法保持原蛇身並新增一格,將新增的一格填黑,形成蛇身變長的效果。
程式碼:
If
body_x(0) = RandNum_x And body_y(0) = RandNum_y Then
length = length + 1
ReDim Preserve body_x(length - 1):
ReDim Preserve body_y(length - 1)
If body_x(length - 2) = body_x(length
- 3) And body_y(length - 2) > body_y(length - 3) Then
body_x(length - 1) =
body_x(length - 2): body_y(length - 1) = body_y(length - 2) + 1
ElseIf body_x(length - 2) =
body_x(length - 3) And body_y(length - 2) > body_y(length - 3) Then
body_x(length - 1) =
body_x(length - 2): body_y(length - 1) = body_y(length - 2) - 1
ElseIf body_x(length - 2) >
body_x(length - 3) And body_y(length - 2) = body_y(length - 3) Then
body_x(length - 1) = body_x(length
- 2) + 1: body_y(length - 1) = body_y(length - 2)
ElseIf body_x(length - 2) <
body_x(length - 3) And body_y(length - 2) > body_y(length - 3) Then
body_x(length - 1) = body_x(length
- 2) - 1: body_y(length - 1) = body_y(length - 2)
End If
Call Randfood
End If
好了,以上8個功能拼湊在一起就能成為一個很陽春的貪食蛇遊戲了。提供完整檔案給大家參考。
留言
張貼留言