VB实现可调节难度的九宫格拼图

时间:2022-12-14 22:48:20

VB实现可调节难度的九宫格拼图

实现本游戏需要熟练掌握paintpicture函数的应用,如果读者对该函数不熟练,需要读一下前面两篇博客哦
http://blog.csdn.net/wf824284257/article/details/53221631
http://blog.csdn.net/wf824284257/article/details/53222996

源码可以在作者的个人主页下载http://www.dawufan.cn/

九宫格拼图,这个游戏,怎么说呢,第一感觉就是给小孩子玩的,很弱智。。。。但是我们是练习代码,所以就拿这个来练练手了,结果在博主写完整个代码并且调试好了以后,自己玩了一下,发现真提莫的难玩。。感觉3*3就是自己的极限了。。。。

先把效果图给出,下面是难度设定为3的时候(3*3)
VB实现可调节难度的九宫格拼图
VB实现可调节难度的九宫格拼图

好,下面我们来分析一下如何做出这个游戏。

1.游戏功能分析

九宫格拼图游戏,默认难度为3,在开始的时候给出一个窗体,用户选择一张图片载入,之后程序会把图片切割成3*3块,并且拿掉右上角这块,之后随机打乱顺序显示在窗体上,这个时候用户可能会点击 显示 菜单 来显示原图,并且根据原图来拼。在拼图过程中,用户会点击某小块图片,如果该图片周围有空位,则交换这块图片以及空位的位置。每次点击后都要判断是否已经拼好了,如果拼好了,就给出胜利提示。

2.抽象化,数据化

可以理解为内层表示与外层表示,内层是基础层或者说运算层,而外层是显示层。

内层主要用到2个矩阵,一个是正确顺序矩阵,一个是随机顺序矩阵,用户点击图片块,相当于对该随机矩阵进行元素交换,每次点击都程序都会将随机矩阵与正确矩阵元素一一对比,若完全相同,则表明拼图成功。

外层是显示层,主要用到paintpicture函数来实现对源图片的切割显示,在随机矩阵元素交换后,相应控件显示的图片也要交换。

3.控件,界面

这里用到2个窗体和一个模块。form1是主窗体,form2用来显示原图,module1用来定义变量以及写一些代码。窗体如下图所示

VB实现可调节难度的九宫格拼图

form1 上设置2个菜单按钮,以及一个picture控件,改名为pic,设置index为0,要在游戏开始后动态加载该pic数组

form2 上放一个picture控件,改名picshow,用来显示原图

3.变量参数

主要游戏变量:

Public MatrixRight() As Integer '正确矩阵
Public MatrixNow() As Integer '当前随机矩阵
Public level As Integer '难度
Public i, j, k As Integer '循环变量

主要界面参数:

Public BW, BH As Integer '大格子宽高,(所有小格子的总宽高)
Public sw, sh As Integer '小格子的宽高
Public lk As Integer '留空
Public ssw, ssh As Integer ' 源图片的每个小格子宽高 source picture’s sw and sh

使用这些界面参数作为基底可以很方便的设计各个控件的位置

4.功能代码介绍

默认难度为3(level=3),切割成3*3共9块,我们需要一个pic控件来存放源图片并且不可见,9个pic控件来显示切割出来的小图片并且可见,所以我们除了放在form1上的pic(0)以外,还需要动态加载9个pic ,pic(0)用来加载源图片,其他9个pic显示的图片都用paintpicture从pic(0)上切割显示。这里pic(0)的autosize和autoredraw 都要设置为true,这是为了完整的加载图片。

首先我们matrixright矩阵赋值如下

1   2   3
4 5 6
7 8 9

再把右上角这一块赋值为-1,用来标识不显示的那块图片

然后通过随机产生matrixnow矩阵,并且把里面的3换成-1。这里随机产生可以通过这样的方式:首先定义一个一维数组randnum(9),则下标为0到8,我们对于矩阵元素1到9来循环。对于1,先产生一个0到8的随机数r,再检测randnum(r)是否有数字了,如果没有就把1放进去,如果有了就再次产生随机数重复以上过程,直到找到一个空位放进去为止,然后再看2. 通过这样的方式在randnum中产生了1到9的随机序列。然后对于matrixnow矩阵,把randnum中的数字一个一个放进去就好了。代码如下

Dim randnum() As Integer
ReDim randnum(1 To level ^ 2)
Dim r As Integer
'creat random num array
For i = 1 To level ^ 2
r = Int(level ^ 2 * Rnd) + 1
If randnum(r) = 0 Then
randnum(r) = i
Else
i = i - 1
End If
Next i
' change "level" to "-1"
For i = 1 To level ^ 2
If randnum(i) = level Then
randnum(i) = -1
Exit For
End If
Next i
'put the num array into the matrixnow
p = 1
For i = 0 To level - 1
For j = 0 To level - 1
MatrixNow(i, j) = randnum(p)
p = p + 1
Next j
Next i

比如产生了这样的随机矩阵

5   4   6
8 2 7
9 3 1

把3变成-1,然后初始的图片就按这个顺序切割显示,-1的那块不显示,就好了。

这样我们内层的初步工作就做完了,下面要显示form1,并且动态加载好控件,设置好他们的位置,以及窗体大小。

lk = 200   '留空200
Form1.Width = 9000 '窗体宽9000,高8000
Form1.Height = 8000
BW = Me.ScaleWidth - 2 * lk '窗体中减去左右的留空,作为所有图片块的总宽
BH = Me.ScaleHeight - 2 * lk
sw = BW \ level '每个图片块的宽,高
sh = BH \ level

For i = 1 To level ^ 2 '加载picture控件,并按index设置位置
Load pic(i)
j = (i - 1) \ level
k = (i - 1) Mod level
pic(i).Top = lk + j * sh
pic(i).Left = lk + k * sw
pic(i).Width = sw
pic(i).Height = sh
pic(i).Visible = True
Next i

当用户点击 打开 时,我们调用commondialog控件来打开图片,该控件需要手动添加

On Error GoTo errhandler
cmdlg.InitDir = App.Path
cmdlg.Filter = "所有文件(*.*)|*.*"
cmdlg.ShowOpen
pic(0).Picture = LoadPicture(cmdlg.FileName)
ssw = pic(0).ScaleWidth / level
ssh = pic(0).ScaleHeight / level

这里我们相当于把pic(0)也进行了3*3切割,ssw表示source pic’s small width ,源图片的小块的宽,ssh表示源图片小块的高。pic(0)的属性要设置为不可见,autosize为true,这样就把源图片原原本本的加载到pic(0)了。

接下来在pic( 1 to 9)中画出相应的图片,这里我们把源图片拉伸到BW*BH的大小后切割,再画出来的,代码为

' paint the level^2 pics out of order

Dim p As Integer
p = 1 ' pic's pointer here

For i = 0 To level - 1
For j = 0 To level - 1
Dim mn As Integer
mn = MatrixNow(i, j)
If mn <> -1 Then ' when -1 no pic
Dim m, n As Integer
m = (mn - 1) \ level
n = (mn - 1) Mod level
pic(p).PaintPicture pic(0).Picture, 0, 0, pic(p).ScaleWidth, pic(p).ScaleHeight, n * ssw, m * ssh, ssw, ssh
End If
p = p + 1
Next j
Next i

这里的paintpicture函数将源图片的相应小块拉伸放入了pic(p)中,关于这个函数如果看不懂,可以参考本文最上面给出的2个链接,这里就不再讲述。

图片的点击事件是比较关键的一点,我们需要判断被点击图片的4个方向是否存在空位,如果存在,就交换位置

Private Sub pic_Click(index As Integer)

i = (index - 1) \ level
j = (index - 1) Mod level
'click on the -1 pic
If MatrixNow(i, j) = -1 Then Exit Sub

'swap judge on 4 derections
Dim m, n As Integer
'left
m = i - 1
n = j
If Judge(m, n, index) Then Exit Sub
'right
m = i + 1
n = j
If Judge(m, n, index) Then Exit Sub
'up
m = i
n = j - 1
If Judge(m, n, index) Then Exit Sub
'down
m = i
n = j + 1
If Judge(m, n, index) Then Exit Sub

'cannot swap,do nothing

End Sub

Judge函数用来判断该方向是否存在空位,如果存在就交换,并判断是否已拼完,返回true,否则返回false。

Private Function Judge(ByVal m As Integer, ByVal n As Integer, ByVal index As Integer) As Boolean

'judge if the matrixnow(i,j) (m,n) can swap
If (m >= 0 And m <= level - 1) And (n >= 0 And n <= level - 1) Then

If MatrixNow(m, n) = -1 Then
'swap pic
SavePicture pic(index).Image, "temp.jpg"
pic(m * level + n + 1).Picture = LoadPicture("temp.jpg")
pic(index).Picture = LoadPicture("")
'swap matrixnow 's value
Dim temp As Integer
temp = MatrixNow(i, j)
MatrixNow(i, j) = MatrixNow(m, n)
MatrixNow(m, n) = temp
Judge = True
Dim x, y As Integer
Dim victory As Boolean
victory = True

For x = 0 To level - 1
For y = 0 To level - 1
If MatrixNow(x, y) <> MatrixRight(x, y) Then
victory = False
Exit For
End If
Next y
If victory = False Then Exit For
Next x


If victory Then
MsgBox "victory!", , "caguatations!"
Kill "temp.jpg"
End If
Exit Function

End If

End If

Judge = False

End Function

这里的图片交换我们是通过这样的方式

SavePicture pic(index).Image, "temp.jpg"
pic(m * level + n + 1).Picture = LoadPicture("temp.jpg")
pic(index).Picture = LoadPicture("")

通过保存后再载入,可以很方便的实现图片的交换。这里为什么不用paintpicture来做呢?原因有2个:一是如果想直接将pic(1)中的图片画到pic(2)中,那pic(1)中的图片不可以是用paintpicture画上去的,也就是说用paintpicture画上去的图片是不算图片的,picture属性仍未0;二是如果想从pic(0)中将对应部分的图片画上去,那还要再进行坐标的转换,好麻烦。。。

所以最终是利用了中间文件的思路,再最后退出的时候,再将”temp.jpg” kill掉就可以了。

5难度设置

写代码的时候要考虑代码的通用性,可变性等,所以虽然游戏的难度默认为3,但是代码中都是用level来表示的,只要之前加个level=3就好了。需要其他难度可以直接改变level值,或者用inputbox输入。

不过博主玩了一下,感觉3*3已经非常难了- -,哎,虽然玩了几遍找到一点技巧,感觉还不错,但是博主把level调成10以后,是这个样子的
VB实现可调节难度的九宫格拼图

啊,对这个游戏绝望了,这个可能拼起来嘛!!

结束

关于这个游戏的主要部分已经说完啦,该游戏源代码在博主的主页http://www.dawufan.cn/下载