WhatsApp网页版登录WhatsApp网页版登录

WhatsApp中文版

贪吃蛇大作战电脑人_贪吃蛇类模块实现_贪吃蛇条件格式显示

好久没更新了,之前一直答应好的贪吃蛇也没做。今天正好在一个问题下聊起了贪吃蛇,下午就抽空做了下。这次同样是用类模块进行实现的。

一、准备界面

我将工作表命名为Game,用一个30*20的界面来做游戏界面,为了更贴近像素格,把列宽调整成了2whatsapp网页版,为了让边界更清楚,我从B2开始画这个界面。

贪吃蛇类模块实现_贪吃蛇大作战电脑人_贪吃蛇条件格式显示

原谅我这个强迫症telegram中文版,上下左右各空了一边.,选择边框加粗这个界面就做好了。图上的“蛇”和“豆”都是后加上去的。

我们在这里规定,蛇身是黑色,豆子是红色。为了方便显示,我们让蛇身显示数字1,豆子显示数字2,然后用条件格式控制单元格的颜色。这和我们在扫雷里的方法是相同的,省去了在代码里设置样式,应该也会加快速度。

二、蛇对象

1、初始化

我们新建一个类模块,命名为Snake。在头部我先要声明两个接口,一个是关于计时器的,一个是关于键盘状态的,代码如下:

#If VBA7 And Win64 Then
  Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
  Private Declare PtrSafe Function GetKeyboardState Lib "user32" (pbKeyState As Byte) As Long
#Else
  Private Declare Function GetTickCount Lib "kernel32" () As Long
  Private Declare Function GetKeyboardState Lib "user32" (pbKeyState As Byte) As Long
#End If

这两在之前俄罗斯方块中我们都用过,就不多做说明了。还有一些对象的属性,如下:

Public interfaceWidth As Integer   '游戏界面宽
Public interfaceHeight As Integer  '游戏界面高
Public firstPointX As Integer  '初始点横坐标
Public firstPointY As Integer  '初始点纵坐标
Public headX As Integer  '头横坐标
Public headY As Integer  '头纵坐标
Public tailX As Integer  '尾横坐标
Public tailY As Integer  '尾纵坐标
Public length As Integer '蛇身长度
Public moveDir As Integer    '移动方向,0123分别代表上右下左
Public movePointX As Integer '移动后横坐标
Public movePointY As Integer '移动后纵坐标
Public moveModel As Integer  '移动方式,1为移动,2为吃
Public gameModel As Boolean  '是否可穿越边界
Public gameArr       '游戏区域
Public snakeBodyArr  '蛇身区域

其实前4个公共成员也可以用Const定义为常量,不过不用太在意了。关于是否可以穿越边界的变量,只是留在这儿,咳咳……其实因为下午时间有限并没有做这个部分。

初始化时我们做了以下几件事:

公共成员赋值设置头尾初始坐标设置初始长度,画出蛇身将游戏区域和蛇身区域放入数组生成一个豆子

Private Sub Class_Initialize()
Me.gameModel = False
Me.interfaceWidth = 30
Me.interfaceHeight = 20
Me.firstPointX = 2
Me.firstPointY = 2
With Worksheets("Game")
  '清空界面
  .Cells(Me.firstPointX, Me.firstPointY).Resize(Me.interfaceHeight, Me.interfaceWidth).ClearContents
  
  '设置头尾初始坐标
  Me.tailX = (Me.interfaceHeight + Me.firstPointY) / 2
  Me.tailY = Me.tailX
  
  Me.headX = Me.tailX
  Me.headY = Me.tailY + 3
  
  '初始长度为4,画出蛇身
  Me.length = 4
  .Cells(Me.tailX, Me.tailY).Resize(1, Me.length).Value = Array(1, 1, 1, 1)
  
  '将游戏区域和蛇身区域放入数组
  gameArr = .Cells(Me.firstPointX, Me.firstPointY).Resize(Me.interfaceHeight, Me.interfaceWidth)
  ReDim snakeBodyArr(Me.length - 1)
  Dim i%
  For i = 0 To Me.length - 1
    snakeBodyArr(i) = Array(Me.headX, Me.headY - i)
  Next i
  
  '生成一个豆子
  Me.New_Bean
  
  '默认方向为右
  Me.moveDir = 1
End With
End Sub

2、生成豆子

初始化方法里有一个生成豆子的方法,按照游戏区域随机生成一个坐标,然后在坐标单元格内写上2.代码如下:

Public Sub New_Bean()
Dim beanX%, beanY%
Do
  Randomize (Timer)
  beanX = Int(Me.interfaceHeight * Rnd) + Me.firstPointX
  beanY = Int(Me.interfaceWidth * Rnd) + Me.firstPointY
Loop While (Bean_Is_Possible(beanX, beanY) = False)
Worksheets("Game").Cells(beanX, beanY) = 2
End Sub

生成豆子的时候要注意一个问题,生成的豆子不能在蛇身上whatsapp网页版,所以需要有一个是否可以放豆子的函数,返回一个布尔值。这个函数只需要遍历蛇身区域的数组,查看是否和随机生成的坐标重合即可。如果把蛇身区域放在字典里,就不需要这样的方法了。

Public Function Bean_Is_Possible(ByVal x As Integer, ByVal y As Integer) As Boolean
Bean_Is_Possible = True
Dim i%
For i = 0 To Me.length - 1
  If snakeBodyArr(i)(0) = x And snakeBodyArr(i)(1) = y Then Bean_Is_Possible = False: Exit Function
Next i
End Function

3、游戏开始

贪吃蛇的游戏也是一个状态机,让蛇不停的移动,让不可移动时状态变为游戏结束。

Public Sub Game_Start()
Dim direaction As Variant
direction = Array(Array(-1, 0), Array(0, 1), Array(1, 0), Array(0, -1))
  
Do
  DoEvents
  '计算移动后头坐标
  Dim movePointX%, movePointY%
  Me.movePointX = Me.headX + direction(Me.moveDir)(0)
  Me.movePointY = Me.headY + direction(Me.moveDir)(1)
    
  '判断是否可以移动
  If Move_Possible Then
    If Me.moveModel = 1 Then
      Call Me.Move
    ElseIf Me.moveModel = 2 Then
      Call Me.Eat
    End If
      
    Me.Sleep (100)
  Else
    Exit Do
  End If
    
Loop While (True)
  
MsgBox "GAME OVER"
End Sub

我们先根据移动的方向moveDir属性,计算出移动后的头部坐标,然后判断是否可以移动。如果在不可穿越边界的模式下超过边界,或者撞到自己,则视为不可移动跳出循环。如果可以移动,就判断移动后的位置是否有豆子,如果有则移动模式变为“吃”,没有则为“移动”。

Public Function Move_Possible() As Boolean
Move_Possible = False
Me.moveModel = 1
If Me.movePointX < Me.firstPointX Or Me.movePointY < Me.firstPointY Or Me.movePointX >= Me.firstPointX + Me.interfaceHeight Or Me.movePointY >= Me.firstPointY + Me.interfaceWidth Then Exit Function
gameArr = Worksheets("Game").Cells(Me.firstPointX, Me.firstPointY).Resize(Me.interfaceHeight, Me.interfaceWidth)
If gameArr(Me.movePointX - (firstPointX - 1), Me.movePointY - (firstPointY - 1)) = 1 Then Exit Function
If gameArr(Me.movePointX - (firstPointX - 1), Me.movePointY - (firstPointY - 1)) = 2 Then Me.moveModel = 2
Move_Possible = True
End Function

4、移动

其实移动很简单,看起来整条蛇都移动了一格,其实只需要给蛇身增加一个头,去掉一个尾。这也是为什么我们在对象属性中要设置头和尾。当然也可以通过蛇身区域数组取得,这样只是更直观一些。

Public Sub Move()
Me.headX = Me.movePointX
Me.headY = Me.movePointY
  
With Worksheets("Game")
  .Cells(Me.tailX, Me.tailY) = ""
  .Cells(Me.headX, Me.headY) = 1
End With
Me.Snake_Body_Update
End Sub

这里有个蛇身更新的方法,它的作用是更新蛇身区域这个数组。这个数组中存放的是蛇身每个点的坐标,我们需要从第一个开始把每个坐标存放的位置后移,这样原来最后的坐标也就是蛇尾就没有了,再把新的蛇头坐标放到第一个位置。

Public Sub Snake_Body_Update()
For i = Me.length - 1 To 1 Step -1
  snakeBodyArr(i) = snakeBodyArr(i - 1)
Next i
snakeBodyArr(0)(0) = Me.headX
snakeBodyArr(0)(1) = Me.headY
Me.tailX = snakeBodyArr(Me.length - 1)(0)
Me.tailY = snakeBodyArr(Me.length - 1)(1)
Worksheets("Game").Range("AF22").Select
End Sub

最后的区域选择,是为了让被选中的单元格固定住,而不至于没法移动。

5、吃

如果碰到豆子,则移动模式变为“吃”。只需要将豆子的单元格变成1,蛇身长度增加1,把原来的所有坐标都后移,让豆子的坐标变为蛇头就可以了。最后别望了再给游戏界面中加一个豆子。

Public Sub Eat()
Me.headX = Me.movePointX
Me.headY = Me.movePointY
Worksheets("Game").Cells(Me.movePointX, Me.movePointY) = 1
Me.length = Me.length + 1
ReDim Preserve snakeBodyArr(Me.length - 1)
Me.Snake_Body_Update
Me.New_Bean
End Sub

6、延时+键盘输入

整个流程基本都完成了,只有在状态机里,移动之后的延时方法Sleep没有说明。延时的部分和之前在迷宫、俄罗斯方块等地方用的相同,只不过这次把利用Worksheet_SelectionChange进行坐标获取的方法改到了延时方法中。

Public 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
  
  Dim keycode(0 To 255) As Byte
  GetKeyboardState keycode(0)
  If keycode(38) > 127 Then Erase keycode: Me.moveDir = 0 '上
  If keycode(39) > 127 Then Erase keycode: Me.moveDir = 1 '右
  If keycode(40) > 127 Then Erase keycode: Me.moveDir = 2 '下
  If keycode(37) > 127 Then Erase keycode: Me.moveDir = 3 '左
    
Loop
End Sub

这么做的原因一开始已经说明过了,贪吃蛇的状态机是一直朝某个方向移动,所以和俄罗斯方块不同的是,键盘输入只需要修改移动的方向就好了,并不需要触发某个移动方法。

三、对象的使用

在模块中新建一个方法,利用声明变量,调用Game_Start方法使游戏开始。在工作表中加一个按钮,调用Game_Start方法就可以了。

Public Sub Game_Start()
  Dim s As New Snake
  s.Game_Start
  
End Sub

以上,方法比较粗糙,还没来得及打磨。还有穿越边界、积分加速等内容没有做,积分加速可以参考俄罗斯方块里的内容,穿越边界应该利用MOD取余就能实现了。

谢谢阅读。

相关文章

«    2025年8月    »
123
45678910
11121314151617
18192021222324
25262728293031

控制面板

您好,欢迎到访网站!
  查看权限

网站分类

最近发表

最新留言

    文章归档

    标签列表

    友情链接