用Excel制作贪吃蛇!


废话不多说,先放成果。在GitHub上查看源代码

点击查看图片

开始编写

阅读此教程,你需要了解

  • 什么是VBA,对VBA初步了解

  • 如何在Excel中编辑VBA,并启用它

否则请另行百度。

最重要的两个函数

RangeCells是整个游戏程序中的核心,它们都能返回一个 表示一个单元格、一行、一列、一个包含单个或若干连续单元格区域的选定单元格范围,或者一个三维区域。(摘自https://docs.microsoft.com/zh-cn/office/vba/api/excel.range(object)

简单来说就是能帮助我们获取到Excel中的每一个格子,以便我们操作他们的属性。

如以下代码:

Cells(2, 22) = "贪吃蛇撞墙过猛,游戏结束"

获取了y坐标为2x坐标为22的单元格,并设置它的文本。(这里可能和我们平时的认知不太一样,Cells函数是y在前x在后的)

初始化

游戏初始化过程的代码如下:

Option Explicit

'定义贪吃蛇坐标变量
Dim snackX(400) As Integer
Dim snackY(400) As Integer
'定义贪吃蛇坐标引索
Dim snackIndex As Integer
'定义贪吃蛇移动变量
Dim snackMoveX As Integer
Dim snackMoveY As Integer
'苹果坐标
Dim appleX As Integer
Dim appleY As Integer
'游戏是否运行
Dim isGameRunning As Integer

'导入win32API模块
#If VBA7 And Win64 Then
  Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
#Else
  Private Declare Function GetTickCount Lib "kernel32" () As Long
#End If

'工具类函数
Private Sub Sleep(numa As Double)
    Dim num1 As Double
    Dim num2 As Double
    Dim numb As Double
    
    numb = 0
    num1 = GetTickCount
    
    Do While numa - numb > 0
      num2 = GetTickCount
      numb = num2 - num1
      DoEvents
    Loop
End Sub

其中,第一行规定全局的变量必须定义后才可以使用,当然取消后代码也能正确运行,但会存在许多潜在的漏洞。

之后,是贪吃蛇和苹果位置信息的定义,以便我们可以全局使用它。需要注意的是,贪吃蛇坐标变量定义了两个长度为400的整形数组,这是经过了计算的,即贪吃蛇沾满格子的长度。

最后,我们导入了kernel32模块。又利用其中的GetTickCount定义了一个Sleep函数,用于延时,以控制游戏帧数。

游戏基础——画布类

'画布类
Public Sub CanvasClean()
    With Range("B2:S19").Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
End Sub

Public Sub CanvasReLoad()
    With Range("A1:T20").Interior
        .PatternColorIndex = xlAutomatic
        .ThemeColor = xlThemeColorLight1
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
End Sub

CanvasClean函数,顾名思义,我们用其清理画布的区域。其中,使用Range("B2:S19")获取了Excel中的格子区域(图中框选区域),并将它清空。点击查看图片

CanvasReLoad中,我们将整个黑框区域恢复原样,及在CanvasClean的基础上,将黑框也重新绘制。

为什么要这么做,给你看个图就知道了:

点击查看图片

主角——贪吃蛇类

'贪吃蛇类
Private Sub TextBox1_Change()
    Select Case TextBox1.Text
        Case Is = "w"
            If snackMoveY <> 1 Then
                snackMoveY = -1
                snackMoveX = 0
            End If
        Case Is = "s"
            If snackMoveY <> -1 Then
                snackMoveY = 1
                snackMoveX = 0
            End If
        Case Is = "a"
            If snackMoveX <> 1 Then
                snackMoveX = -1
                snackMoveY = 0
            End If
        Case Is = "d"
            If snackMoveX <> -1 Then
                snackMoveX = 1
                snackMoveY = 0
            End If
    End Select
    TextBox1.Text = ""
End Sub

Public Sub snackCreate()
    snackIndex = 3
    Dim i As Integer
    Dim x As Integer
    Dim y As Integer
    x = Int(Rnd * 13) + 3
    y = Int(Rnd * 13) + 3
    For i = 0 To snackIndex
        snackX(i) = x
        snackY(i) = y + i
    Next
End Sub

Public Sub snackMove()
    Dim i As Integer
    For i = snackIndex To 1 Step -1
        snackX(i) = snackX(i - 1)
        snackY(i) = snackY(i - 1)
    Next
    snackX(0) = snackX(0) + snackMoveX
    snackY(0) = snackY(0) + snackMoveY
End Sub

Public Sub snackDraw()
    Dim i As Integer
    For i = 0 To snackIndex
        Cells(snackY(i), snackX(i)).Interior.Color = 255
    Next
End Sub

Public Sub snackHitWall()
    If snackX(0) = 1 Or snackX(0) = 20 Or snackY(0) = 1 Or snackY(0) = 20 Then
        Cells(2, 22) = "贪吃蛇撞墙过猛,游戏结束"
        isGameRunning = 0
    End If
End Sub

Public Sub snackEatApple()
    If snackX(0) = appleX And snackY(0) = appleY Then
        appleCreate
        snackIndex = snackIndex + 1
        Cells(4, 22) = Int(Cells(4, 22).Value) + 1
    End If
End Sub

Public Sub snackHitHimself()
    Dim i As Integer
    For i = 1 To snackIndex
        If snackX(0) = snackX(i) And snackY(0) = snackY(i) Then
            Cells(2, 22) = "贪吃蛇把自己吃了,游戏结束"
            isGameRunning = 0
        End If
    Next
End Sub

如果你熟悉VB,那你一定看出来了,TextBox1_Change是TextBox1中的文本改变时自动调用的一个过程。我们在这里进行判断,已根据WASD的方向键调整贪吃蛇的移动量,最后再将其内容清空,以便下一次检测

其次,就是故名思意了:

  • snackCreate——创建贪吃蛇
  • snackMove——根据贪吃蛇的移动量移动贪吃蛇
  • snackDraw——绘制贪吃蛇
  • snackHitWall——检测贪吃蛇是否撞到墙
  • snackEatApple——检测贪吃蛇是否吃到苹果
  • snackHitHimself——检测贪吃蛇是否把自己吃了

食物——苹果类

'苹果类
Public Sub appleCreate()
    appleX = Int(Rnd * 15) + 3
    appleY = Int(Rnd * 15) + 3
End Sub

Public Sub appleDraw()
    Cells(appleY, appleX).Interior.Color = 100
End Sub

与贪吃蛇基本相同,但简单许多:

  • appleCreate——创建苹果
  • appleDraw——绘制苹果

游戏中的Main函数——游戏类

'游戏类
Public Sub restGame()
    snackMoveY = 0
    snackMoveX = 1
    Cells(2, 22) = "游戏中"
    Cells(4, 22) = 0
End Sub

Public Sub beginGame()
    isGameRunning = 1
    restGame
    
    CanvasReLoad
    
    snackCreate
    appleCreate
    
    Do While isGameRunning = 1
        CanvasClean
        
        appleDraw
        
        snackMove
        snackDraw
        
        snackHitWall
        snackEatApple
        snackHitHimself
        
        Sleep (300)
    Loop
End Sub

Public Sub stopGame()
    isGameRunning = 0
    Cells(2, 22) = "游戏结束"
End Sub

restGame重置游戏,stopGame停止游戏。

beginGame函数的逻辑为。

start=>start: 开始游戏
is_gameRunning_true=>operation: 将游戏状态设置为Ture
restGame=>operation: 重置游戏
CanvasReLoad=>operation: 重置画布
snackCreate=>operation: 创建贪食蛇
appleCreate=>operation: 创建苹果
is_gameRunning=>condition: 游戏状态是否为True
CanvasClean=>operation: 清空画布
appleDraw=>operation: 绘制苹果
snackMove=>operation: 移动贪吃蛇
snackDraw=>operation: 绘制贪吃蛇
snackHitWall=>operation: 检测贪吃蛇是否撞到墙
snackEatApple=>operation: 检测贪吃蛇是否吃到苹果
snackHitHimself=>operation: 检测贪吃蛇是否把自己吃了
sleep=>operation: 延时300秒
end=>end: 游戏结束

start->is_gameRunning_true->restGame->CanvasReLoad->snackCreate->appleCreate->is_gameRunning
is_gameRunning(yes)->CanvasClean->appleDraw->snackMove->snackDraw->snackHitWall->snackEatApple->snackHitHimself->sleep(left)->is_gameRunning
is_gameRunning(no)->end

文章作者: peler
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 peler !
评论
  目录