目录

分享一个基于labview的2048小游戏附详细教程代码

分享一个基于labview的2048小游戏(附详细教程+代码)

游戏界面是参照官方标准的2048来设计的,话不多说,先看一下游戏效果!

https://i-blog.csdnimg.cn/blog_migrate/a93ffc0c3d5681c14a1abd199a0b9213.gif

这个小游戏是基于labview 2020SP1开发的,下面我详细的介绍一下游戏的整个制作过程 。

首先明确程序的设计思路:

第一:需求分析,游戏规则及需要的功能;

第二:前面板设计,游戏界面要做成什么样子;

第三:需求转换,将需求转换为代码;

第四:程序框图设计,完成代码编写;

最后:调试bug。

1 需求分析

1.1游戏规则

我相信很多人都玩过这个游戏,游戏规则大家也很熟悉,就是通过上下左右移动,将同行或同列相同数字叠加变成更大的数字比如2048,4096,8192等, 这里涉及到移动的算法,也是程序最核心的地方!

完成一次有效的移动后,棋盘中空白格子需要随机生成一个数字(一般是2或4),如果棋盘所以格子全部占满且无法移动,那么恭喜你,游戏结束!

1.2其他功能

除了游戏规则外,游戏本身需要计分功能及得分规则(记录当前得分,历史最高得分),游戏退出后,重新打开程序能够将上一次的得分记录及棋盘状态还原,并能重新开始新游戏。

2 前面板设计

需求分析之后我们知道了游戏规则以及要实现的功能,现在我们就可以开始进行前面板的布局了,首先我们需要

一个4*4大小的数字棋盘

,这里我们可以使用

2维数组

,然后是需要两个显控件来显示

当前得分

历史最高得分,

其次需要

两个布尔按钮分别实现重开功能与退出游戏功能,最后是建立一个标签作为游戏标题。

2.1棋盘设计

如果我们用基本的二维数字数组作为游戏棋盘,那界面是相当丑陋,可以看一下效果:非常难看,而且数字数组有个缺点,就是你没法将指定行列设置为空白,必须显示数字。

https://i-blog.csdnimg.cn/blog_migrate/6cb7cf35c0ddc6f21eb6b797ce7051b5.png

为了用户的更好的游戏体验我们可以自定义一个二维图片数组,我们可以参照官方的2048游戏界面,利用PS把制作出不同背景颜色的数字,然后新建自定义图片控件,把所有数字放到图片控件里面。

我们新建一个自定义控件,在经典控件面板中添加一个图片下拉列表,把高度与宽度设置 (100*100) ,然后利用工具选版把控件边框设置为透明,效果图如下:

https://i-blog.csdnimg.cn/blog_migrate/544ea8ef7dfe3fdac8ca17b55f74f4d8.png

接下来我们利用PS制作数字图片,图片样式我们直接参考官方2048的界面进行制作。

https://i-blog.csdnimg.cn/blog_migrate/ca11c128ba38c7084d66f4ce88e79aed.png

官方2048游戏界面

我们发现,不同的数字的背景颜色都不一样,打开PS,开始制作,PS的详细制作过程我这里就不细讲了, 但是需要注意一点我们新建图层的大小必须要之前labview里面的自定义下拉图片控件大小保持一直,也就是像素大小为100*100,这样子才能保证导入之后图像不会失真!

https://i-blog.csdnimg.cn/blog_migrate/126418ebdf33d8228b223f84c88ca35c.png

我们只需要一个文字图层跟背景图层就行了,然后根据不同图层组合将所有数字导出到本地, 注意!这里需要一张无数字的图片来作为空白背景。

https://i-blog.csdnimg.cn/blog_migrate/e32bdfea4084743dc9d57e303f1d987e.png

我这里只做到了8192,也就是说玩到8192后,游戏就通关了,当然你们也可以新增数字或者更改图片样式来增加游戏的可玩性(比如换成姓氏,朝代等等)。

图片设计完成后,就可以导入到刚刚新建的下拉图片控件中去了 。我们依次将空白图片,2 ,4,8,16…8192按顺序导入,有人肯定会问为什么要从小到大的顺序导入?这个到后面程序设计的时候我再解释,肯定是方便才这样子做。

https://i-blog.csdnimg.cn/blog_migrate/d1dfab499d9f2fa8a285e0cc851b79cd.png

最终效果图如下

https://i-blog.csdnimg.cn/blog_migrate/59f674bd0cc525a02d0251697af30512.png

把所有图标导入完成后, 我们把控件类型设置为“严格自定义类型” ,这样子后面我们如果需要新增或更改图片,所有调用这个子vi的父级vi都会自动更新,非常方便!

完成编辑后,记得保存!

2.1搭建主程序前面板

前面我们已经明确了前面板所需要的控件:

1个数字棋盘:二维图片数组;

1个得分显示控件;

1个历史最高得分显示控件;

1个布尔按钮:新游戏;

1个布尔按钮:退出;

1个标题标签:2048;

我们新建一个vi,并新建以上控件到前面板中去,

这里所有的控件推荐使用经典面板框的,因为方便上色。

其中棋盘的构建方法我介绍一下,我们新建一个二维空数组,并将该数组边框设置为透明,将之前做好的“严格自定义类型”的下拉图片控件拖动到该数组中去,将其展开为四行四列,效果图如下;

https://i-blog.csdnimg.cn/blog_migrate/30db98792653de355b5260d2477e50aa.png

棋盘设计

这里因为没有对数组进行初始化赋值,所以系统默认为空数组,我们可以手动为其赋值,选中任意方格更改图片样式即可。

https://i-blog.csdnimg.cn/blog_migrate/fb85392f1730732b7c6d77e607cadf21.png

更改一下数组标签名称,并将数组索引框与数组名称隐藏就可以了。我们接下来放置剩余的控件,我这里就直接放效果图了。

https://i-blog.csdnimg.cn/blog_migrate/4984a1beaee4633e7151efe63e26f1d1.png

现在我们前面板所需要的控件全部准备好了, 但是!界面显得十分不和谐,非常难看,如果你是用户,肯定不会去玩这个游戏。

所以为了提高用户体验,我们需要对界面进行重新设计与布局(我不是学UI的,所以只能参考网上已有的界面进行更改),这里我还是简单说一下操作方法。

得分控件与最高得分控件的设计

我们这里采用与棋盘风格保持一致的做法,将控件数字字体调节至合适大小(选中数字,同时按住“ctrl”与“+”),格式加粗并居中,调节宽度,并使用工具面板对其上色(根据你的爱好随意上色)。其文字标签采用相同的处理方法,放置到数字显示框上面,我们看一下效果:

https://i-blog.csdnimg.cn/blog_migrate/1ca77e09c51eb23296d19d47565ea9dc.png

这里注意一点,不管是得分还是最高得分,其数值都是比较大的,所以数值类型推荐使用U32 ,

接下来是两个布尔按钮的设计

方法跟上面一致,主要是调节文本大小以及上色,我就不重复了,最后我们需要一个标题标签说明一下游戏名称(看个人,也可以不需要这个)。

https://i-blog.csdnimg.cn/blog_migrate/432f89298a6a0f6f996743d4b0c20b6b.png

这里所以控件外观设计已经完成了,但是观察了半天,感觉还是有点不好看,一是界面太大,二是各控件之间布局不协调,于是我们还需要耐心的进行调整。

later。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

https://i-blog.csdnimg.cn/blog_migrate/88a3efc5ad2f7bb927b4bbd7e7ca9169.png

经过不懈的努力,我们终于完成了前面板的设计,其实对于labview程序开发来说,前面板设计通常都是程序设计的第一步,也是非常重要的一步,我们需要有足够的耐心去把它做好,这样子对后面的程序编写能提供极大的便利!

3 程序框图设计

3.1需求转化

程序设计之前,我们把需求转化为算法:

1.因为这是在桌面平台上运行,所以只能通过键盘按钮来控制移动,建议使用方向键“↑”、“↓”、“←”、“→”来实现。

2.当按方向键“↑”的时候,棋盘以列为单位,从上往下将相邻且相同的数字组合成新的数字,赋值给两者偏上(列索引偏小)的格子。

3.当按方向键“↓”的时候,棋盘以列为单位,向下移动,从下往上将相邻且相同的数字组合成新的数字,赋值给两者偏下(列索引偏大)的格子。

4.当按方向键“←”的时候,棋盘以行为单位,向左移动,从左往右并将相邻且相同的数字组合成新的数字,赋值给两者偏左(行索引偏大)的格子。

5.当按方向键“→”的时候,棋盘以行为单位,向右移动,从右往左将相邻且相同的数字组合成新的数字,赋值给两者偏右(行索引偏小)的格子。

6.移动棋盘结束后,则需要将所有合并的数字转换为得分,并判断游戏是否结束或通关。

7.如果当前得分大于最高得分,需要将当前得分赋值给最高得分。

8.单击“新游戏”按钮,重新开始游戏;

9.单击“退出”按钮,退出程序,保存当时棋盘内容,得分,最高得分,下次重启后恢复!

10.重新进入游戏后,恢复上一次游戏记录。

其实看似很简单的需求,我们好好整理一下,发现其实要做的功能并不少,好了我们现在就开始一条一条的实现它吧!

3.2程序设计

我们打开程序框图(Ctrl+E) ,创建所有控件引用,并捆绑成簇进行管理,把生成的簇常量保存到自义定的严格控件中去,这样子一旦需要新增或删除控件,我们只要更新自定义控件就行了。

https://i-blog.csdnimg.cn/blog_migrate/18df3b479bb27b8ff90b3308a55a4db9.png

https://i-blog.csdnimg.cn/blog_migrate/2f2ad5006e54d65ed32b598e4887c0dd.png

这里说一下我为什么要创建控件的引用,而不直接操作控件,其实对控件引用进行编程就相当于C语言中直接对地址进行操作一样,无论你在哪个vi里面修改控件引用的方法属性,都会直接对该控件进行更改 ,非常方便!

在程序框图中,我们应该有注意到我多了一个 历史记录 的数组控件,这个用于实现返回上一步操作的功能,但是前面板中被隐藏了,主要是调试的时候可以使用,因为程序出bug后,你非常有必要知道上一步棋盘的状态,从而判断当前操作是否有问题。

3.2.1初始化

程序初始化是对前面板中的控件赋默认值,包括棋盘,得分,最高得分,布尔按钮状态。

我们在需求分析第10条中了解到,进入游戏后,程序需要将上一次游戏的状态恢复,游戏状态理解为:当前棋盘数组 的值,得分值,最高得分值。

所以我们需要做一个vi来对读写这些值,那怎么应该怎么写呢?

https://i-blog.csdnimg.cn/blog_migrate/b4768a2d5c654163bfd3de3924e3edea.png

写记录

很简单,我们把棋盘数组,得分,最高得分打包成簇,然后存到本地的.xml文件中,我这里文件名称为“2048 record.xml” 。

同样的读记录我们也写一个

https://i-blog.csdnimg.cn/blog_migrate/e435dbc0b0e1bd993d0c9f9939e51793.png

读记录

这样子我们就完成了两个功能,保存当前游戏记录、恢复当前游戏记录。接下来我们就知道游戏初始化需要做什么了吧。

第一:初始化两个布尔控件,并设置当前VI运行时窗口居中。

第二:恢复游戏状态, 这里可能有人有疑问,假如我是第一次玩这个游戏,根本就没有游戏记录,那应该怎么办呢,其实这个问题很好处理,那就是读xml文件之前先判断该文件是否存在,如果不存在,那么就新建,并且对棋盘数组、得分、最高得分赋默认值。

第三:新游戏状态下,需要随机生成两个数字(2或4);

https://i-blog.csdnimg.cn/blog_migrate/429555a8c714dd80020626d6e551b42a.png

https://i-blog.csdnimg.cn/blog_migrate/f2de257cfe900dedfb44378763868aa1.png 好的,程序初始化完成了, 这里不知道有人注意到没有,不管是布尔控件的初始化还是xml文件的读写,其实都是在同一个vi里面,我用了一个枚举输入控件把不同的功能的程序框图放到了不同的条件结构里面。

https://i-blog.csdnimg.cn/blog_migrate/8a1ad4362cc7757ee63c2ab57475730f.png

初始化完成后我们运行一下程序看看效果。

https://i-blog.csdnimg.cn/blog_migrate/ade3c6765aaa419f5514814d14b11c7a.png

3.2.2功能实现

我们采用while循环+事件结构的基本框架来捕获键盘按下事件以及两个布尔按钮按下的事件。

https://i-blog.csdnimg.cn/blog_migrate/f0d1c99316eb7272f7c3b4b442e18586.png

https://i-blog.csdnimg.cn/blog_migrate/98bc3c0e866e59fcc655c6acf3c2dfde.png

https://i-blog.csdnimg.cn/blog_migrate/c80e34c83e369c76a15154e94ebd7804.png

三个基本的事件结构新建完成后, 我们就可以开始逐个编写每个事件对应功能的代码。

新游戏

将当前棋盘数组,得分,最高得分保存到.xml文件中(直接调用写历史记录vi),重新赋值棋盘数组,当前得分置零。

https://i-blog.csdnimg.cn/blog_migrate/169bbac7e58ea3f0bfd40038e3a5ae73.png

https://i-blog.csdnimg.cn/blog_migrate/c55dbe8f4ac592fa5e3e696a35820635.png

退出

退出游戏之前,我们需要保存一下棋盘信息、得分、最高得分。直接调用写历史记录vi。

https://i-blog.csdnimg.cn/blog_migrate/dbeb170b39ee88933c8c13ce86d5cb5a.png

键入值

这是游戏最核心的功能,我们再分析一下算法:

1.当按方向键“↑”的时候,棋盘以列为单位,从上往下将相邻且相同的数字组合成新的数字,赋值给两者偏上(列索引偏小)的格子。

2.当按方向键“↓”的时候,棋盘以列为单位,向下移动,从下往上将相邻且相同的数字组合成新的数字,赋值给两者偏下(列索引偏大)的格子。

3.当按方向键“←”的时候,棋盘以行为单位,向左移动,从左往右并将相邻且相同的数字组合成新的数字,赋值给两者偏左(行索引偏大)的格子。

4.当按方向键“→”的时候,棋盘以行为单位,向右移动,从右往左将相邻且相同的数字组合成新的数字,赋值给两者偏右(行索引偏小)的格子。

这里我们要知道一个棋盘数组的机制,也就是不同的数字在棋盘数组里面的值代表多少,因为我们编程最终识别的是数组里面的值而不是图片,这里我做了一个表。

https://i-blog.csdnimg.cn/blog_migrate/319a9288355ac1ffb6d8e177ab140fe7.png

这个顺序是跟之前我导入图片的顺序一致的,现在我解释一下为什么这样子做?

我们可以看出任意相邻的两个数字对应到数组中的值都相差1,那么每当我合并数字的时候,我只需要将该数字加1就能得到合并的新值了,而对应的得分正好是2的N次幂(N代表:新值) 。熟悉这个规则之后,我们就可以进行代码编写了。

https://i-blog.csdnimg.cn/blog_migrate/2103e95c4fe5b0434b3e756954f3b132.png

当扫码代码为72(↑)、80(↓)、75(←)、77(→)时执行程序代码,这里以“↑”为例讲一下具体的算法。

当程序检测到“↑”按下后, 棋盘应该以列为单位:往上移动,我们先把二维数组中的每一列按左往右的顺序取出来,然后每一列中的每个元素与下一个元素作比较,可能的情况如下:

case A:array[N]=0,结束循环,N+1;

caseB:array[N]≠0,判断

array[N]=array[N+1]?若相等,将两个数相加,和赋值给array[N],并将array[N+1]赋值为0,结束循环,N+1。

caseC:array[N]≠0,判断

array[N]=array[N+1]?若不相等,结束循环,N+1。

循环结构将输入数组添加移位寄存器,因为每一种情况都有可能改变数组的值,当条件满足caseB时,将新值N以2的指数形式计算输出为得分值。

因为这里是以列为索引输入的一维数组,经过for循环的索引通道后将变成二维数组,但是新的二维数组与原来的二维数组为行列倒置关系,所以需要倒置一下,如果是左右移动,则是以行索引,因此不用倒置。

当方向为“↓”时,按列索引后,元素顺序是从上往下走的,所以我们需要反转一下数组顺序,方向为“→”时也是同样的道理。

当数字合并完成后,我们发现值虽然变化,但是位置却没有改变,比如往上移动时,所有的数字都应该靠上,所以还需要加一个数字移动算法。

https://i-blog.csdnimg.cn/blog_migrate/88702104c0af595018cf321f676e883b.png https://i-blog.csdnimg.cn/blog_migrate/4baa7adc0434529795952e075532937f.png

当往上或左移动时,有效数字应该在前面,空数字在后面,当往下或右移动时,顺序则相反。

最后我们把移动后的数组赋值给棋盘,并计算一下得分。

https://i-blog.csdnimg.cn/blog_migrate/d7338c8830bafc902f3a24a1d716d6de.png

随机生成数字

棋盘移动完成后,我们需要在棋盘空白区域生成一个新的数字2或4,前提是棋盘移动有效,什么意思?也就是我按下方向键之后,棋盘内容发生改变才算有效,否则无效,如果移动无效,则不需要生成新的数字。

那么怎么判断移动是否有效呢?我们可以将移动后的数组与移动前的数组作比较,如相等则无效,不等则有效。

https://i-blog.csdnimg.cn/blog_migrate/80e8a019dd3ecf6bea64cd05019ce71c.png

随机生成数字

我这里用来一个0-100的随机数生成器,如果随机数<70,则生成2;随机数>70则生成4;

好了我们最好看一下键入值的程序程序框图

https://i-blog.csdnimg.cn/blog_migrate/15efd9a647d7ce97f103dc83f4cd4840.png

撤销功能

这里一个调试功能,用于返回上一步棋盘状态,我利用的一个三维数组来存储棋盘每次移动后的数据,该三维数组中倒第二数则代表上一步的棋盘数据,这里我就不详细介绍了。

说明

最后说明一下,labview这款工具主要是用于测量或控制系统开发的,用于开发游戏纯粹是个人爱好,希望大家不喜勿喷!

源代码我附在文章最后,低于 labview2020 SP1的版本是打不开的!

我的文字表达能力有限,如果大家有什么疑问欢迎在评论区提出,谢谢!

源代码

链接:

提取码:njgs