【木棉花】#打卡不停更#HarmonyOS小游戏项目——数独Sudoku(5) 原创 精华
前言
Hello,各位好久不见!
非常抱歉,这段时间作者在忙于其他事情,所以一直没有在社区更文。
时间过得很快,HarmonyOS与OpenHarmony也发展地很快,目前DevEco Studio的鸿蒙SDK也已经更新到API8的版本了。对于鸿蒙操作系统的蒸蒸日上,我感到非常喜悦。
最近的一段时间,我重新阅读了放在IDE中的数独游戏项目的代码,发现自己曾经写的代码其实挺烂的。事实上,我是在接触了鸿蒙的前端后,才开始尝试去学习Java语言并利用Java创建UI的。所以在写这个项目时,我的Java仍处于比较菜的水平,权限修饰符用的很乱,并且有些代码虽然能运行,但也写的不简洁或者不合理,所以近期我对这个项目的代码进行了许多优化。实际上,作为一个学习者,任何人在编程的初期都不可避免地会写一些烂代码,以及踩一些坑。我们进步的过程,不仅是学习一些未接触过的新知识,更重要的是在之前所写过的代码中不断优化,并在这个过程中不断提炼新的计算机思维。
另外,因为DevEco studo的SDK8版本已经将Java移除了,这意味着在IDE中用Java代码编译的程序只能运行在SDK7以前的华为机型,所以笔者在更新完关于数独项目的文章后,就暂时不继续分享有关Java的代码了,而是先尝试去学习与分享关于JavaScrip与ets的内容。
上期的内容回顾——>>https://ost.51cto.com/posts/15252
正文
在本期的分享中,笔者将继续完善项目的相关功能,并制作判定游戏是否通关的功能。
定义两个重要的数组
打开GameAbilitySlice,并在合适的位置定义两个二维数组——grids_win和grids_input。注意,这两个数组是作为全局变量定义的,他们不能定义在生命周期函数或其他函数内。
在这两个新定义的数组变量,grids_win代表储存了数独答案的二维数组,而grids_input代表用户在游戏交互过程中将要改变的数组。这两个数组在项目中主要用于判定游戏的胜利与否,而判断逻辑是这样的:如果grid_input中每行每列的元素都等于grids_win中每行每列的元素,这就意味着用户在数独网格填入的数字与答案一致,此时游戏胜利;否则,游戏未成功。
在定义grids_win与grids_input前,我们在之前的文章中已经定义了grid_c0,而grid_c0用于生成网格区域中的数独题目的。接下来,我们再定义grid_c0数组所对应的答案数组——grid_v0(注意,grid_c0与grid_v0均是定义在onstart函数内的局部变量):
然后,我们再进行如下赋值操作(笔者也惊讶地发现,Java的数组赋值竟然可以如此轻松快捷qwq):
这样,grids_input和grids_win就被输入对应的数据了。
或许读者会问,为什么不直接把grid_c0和grid_v0分别作为用户交互的数组和答案数组来使用呢?原因是,grid_c0与grid_v0只是分别作为这个游戏的某一个一个关卡的题目与答案,在后文,笔者会导入更多的题目与答案,所以我们需要另外定义grid_input与grid_win作为两个全局变量,当关卡不同时,这两个变量也就分别负责储存不同的题目与答案,以及参与判断游戏是否胜利的逻辑判断过程。
创建三个功能按钮
我们先找到之前创建的6个圆形button对象(即用于在网格区域输入数字的Button组件),并在这6个圆形button对象的监听器内各加入一行指令(即下面代码中“//”前的部分):
指令中的变量j1和变量k1,就是笔者在上期内容中利用Text组件转换所得的的每个网格的位置信息(详细原理详见上期内容)。这样以后,用户每次在某个区域上输入数字(1到6的整数)时,数组grids_input的对应存储位置也会被输入相应的数字元素。
完成上述操作后,我们开始另外创建三个新的按钮,每个按钮都负责不同的功能(如图箭头所指部分):
首先,我们为将要创建的Button对象定义基本的背景元素:
然后通过代码布局创建这三个按钮(需要写入的Button对象的方法都差不多,只是一些参数不同):
这样之后,我们就新创建了三个按钮。其中,第一个”清除“按钮用于在网格区域的获焦网格上输入空字符串,这意味着我们实现了清除白色网格内已输入数字的功能。在清除白色网格内的数字的同时,此按钮还将grid_input(即在游戏过程会被用户修改参数的矩阵)对应位置的元素赋值为0,确保grid_input内的对应元素可以在清除功能被执行时更新(否则游之后的游戏判断功能会出bug)。
第二个”重新开始“按钮用于让应用从当前的GameAbilitySlice跳转至另一个新生成的GameAbilitySlice,能够实现页面刷新的功能。由于在之前的文章中,我们在onBackground回调中加入了销毁指令,所以系统由旧的GameAbilitySlice导航至新的GameAbilitySlice时,旧的GameAbilitySlice由于进入background态后会启用onBackground回调,进而被销毁。假如之前我们没有添加销毁指令,那么用户每点击一次”重新开始“的按钮,AbilitySlice的实例栈就会堆放一个GameAbilitySlice,这是非常浪费系统内存资源的。
第三个按钮是”提交“键,我们已经写入了基本的方法,但他的监听器内是未添加任何代码的。接下来我们就在这个button对象的监听器内加入一些指令,以实现判断游戏是否成功的功能。
制作判定游戏成功的函数
首先,我们在合适的位置定义一个布尔型函数:
这个函数是返回布尔值的函数,其封装的代码也非常简单,就是让grid_win矩阵与grid_input矩阵的每个位置的元素进行比较,如果经过循环判断为全部相等,那么这两个矩阵就完全相等,即满足了游戏胜利的条件。值得一提的是,由于此函数封装的代码包含的两个变量——grids_win与grids_input是全局变量,所以笔者并没有将执行不同功能的代码完全模块化,这意味着如果这两个全局变量在某些指令中被修改,Gamesuccess()是有几率受到影响的,这是项目中不足的地方。
接着,我们通过代码布局初始化两个弹窗(弹窗必须定义在 button_pr之前):
最后,我们在“提交”按钮的监听器内加入指令:
可以看到,如果Gamesuccess()函数返回的值是true,那么系统就会调用Dialog_win的show()方法,将Dialog_win展示在屏幕前以提示游戏成功;如果返回的值是false,系统则调用 Dialog_fail的show()方法,将Dialog_fail展示在屏幕前以提示游戏未成功。这样一来,游戏成功与否的判断逻辑便得以成功搭建。
经过上述的所有操作后,我们可以打开API为6的模拟机试玩,效果图如下:
因为SDK6版本的P40模拟机在近期被停用了,所以我只能用平板模拟机调试程序(/(ㄒoㄒ)/~~),图片看起来可能有点怪怪的。
结语
本期的内容就先分享到这里,更多关于数独小游戏项目精彩的内容我将在下期继续为大家揭晓。
不断的审视过去的自己,也是提升自己的好方法,向楼主学习
Java和ets都要会一点,开发更方便