【木棉花】#夏日挑战赛# 鸿蒙小游戏项目——数独Sudoku(2) 原创 精华
前言
在上期内容的分享中,笔者介绍了如何搭建基础的页面框架(为之后的开发做准备),以及应用图像和标签的修改、应用的全屏化。而在本期,笔者就在上期的基础上继续展开数独小游戏项目的搭建。
上期的内容回顾——>>https://ost.51cto.com/posts/14383
正文
本期,笔者将介绍如何利用代码布局创建网格区域的UI。
首先,笔者所说的网格区域指的是下图被圈出的部分:
事实上,因为网格区域用于承载数独的题目,它同时也是玩家主要面向的部分,所以网格区域的逻辑就是这个项目最核心的功能。网格区域中有两种颜色的网格,其中,蓝色网格内的数字是应用为用户提供的提示数字,白色网格则需要用户根据数独的规则合理填入数字,两种格子的数量加起来共计64个。而现在我们面临的问题是——我们如何将这个6x6的平面网格系统搭建起来呢?
笔者的思路是,先设计网格区域的UI,再完善网格区域的交互逻辑。而本期将介绍的内容就是如何设计网格区域的UI。
网格区域中共有36格子,那么这些格子需要用什么UI组件做呢?Button组件无疑可以尝试一下。那么我们接下来所要做的就是把Button组件设计成每一个格子,然后让他们按一定的顺序排起来,组成一个网格系统。由于格子的数量较多,所以我们不能用XML布局一个一个定义,这样不仅效率慢,而且占用内存。而如果我们选择使用Java代码布局的话,我们就可以利用for循环来渲染button组件,以此做到高效简洁。
当然,我们还面临另一个问题——设计好的格子应该通过什么布局排起来呢?因为我们是通过for循环来生成格子的,在这样的前提下,只有坐标布局才能与for循环无缝融合。
以下是通过代码布局设计网格区域的UI的具体步骤。
完善GameAbilitySlice
由于数独小游戏项目的游戏界面是用GameAbilitySlice承载的,所以我们首先要完善之前新创建的GameAbilitySlice。打开GameAbilitySlice,将代码修改为如下:
package com.example.project.slice;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
public class GameAbilitySlice extends AbilitySlice {
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
}
@Override
protected void onBackground() {
super.onBackground();
}
}
这样以后,GameAbilitySlice就继承了AbilitySlice的类,并且它被写入了onStart和onBackground两个生命周期回调函数。
设计题目
在设计网格区域之前,我们需要先创建一个数独题目(这样之后每个格子的颜色和数字才能被确定),这个题目的信息需要用数据承载。
在这里,我们将利用数组的形式存储数独题目。定义一个6x6的数组——将代码修改为如下:
package com.example.project.slice;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
public class GameAbilitySlice extends AbilitySlice {
//定义一个数组
int[][] grid_c0=new int[6][];
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
//为数组赋值
grid_c0[0]=new int[]{0,0,0,0,1,0};
grid_c0[1]=new int[]{1,0,2,4,0,0};
grid_c0[2]=new int[]{6,2,3,0,0,5};
grid_c0[3]=new int[]{5,0,0,2,3,6};
grid_c0[4]=new int[]{0,6,4,3,5,0};
grid_c0[5]=new int[]{3,1,0,5,0,4};
}
@Override
protected void onBackground() {
super.onBackground();
}
}
可以看出,我们首先在GameAbilitySlice的内部定义了一个列数为6的数组grid_c0(即数组每行有六个数字),然后我们又在onStart函数内部为这个数组的每一列(第0列到第五列)赋值,这样grid_co就可以写成矩阵:
0 1 6 5 0 3
0 0 2 0 6 1
0 2 3 0 4 0
0 4 0 2 3 5
1 0 0 3 5 0
0 0 5 6 0 4
通过代码布局的方式创建GameAbilitySlice的UI界面
首先,在onStart内(”为数组赋值”的下方)加入下列代码:
PositionLayout layout1=new PositionLayout(getContext());
layout1.setHeight(ComponentContainer.LayoutConfig.MATCH_PARENT);
layout1.setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
这样做的目的是——在onStart的方法内创建一个PositionLayout的对象。并且,这个对象的高度和宽度继承了父组件(其父组件可以认为是手机屏幕)的尺寸。PositionLayout的中文名是坐标布局,它属于一种容器组件[容器组件是用来放置其它常用子组件(如按钮组件,文本组件)的]。我们这里之所以用坐标布局,而不是用其它布局,是因为坐标布局可以用坐标(x,y)来确定其子组件的位置。相较于方向布局和依赖布局,坐标布局更加直观和精确,这也是我们选用坐标布局的主要原因。
创建网格区域
首先,我们事先定义一些数据,以便在后面使用:
int x;
int y;
int number;
String string0;
接着,我们为Button组件创建两种背景元素:
ShapeElement element0=new ShapeElement();
element0.setRgbColor(new RgbColor(255,255,255)); //设置RGB颜色(白色)
element0.setStroke(5,new RgbColor(0,0,0)); //设置边框的厚度和颜色(黑色)
ShapeElement element3=new ShapeElement();
element3.setRgbColor(new RgbColor(0,125,225)); //设置RGB颜色(蓝色)
element3.setStroke(5,new RgbColor(0,0,0)); //设置边框的厚度和颜色(黑色)
于是,我们得到了element0和element3两种背景元素,他们分别可以把Button组件装饰成蓝色网格状和白色网格状。
之后,我们通过双重for循环来渲染Button组件,并在坐标布局的协助下,利用这些Button组件构成一个网格:
for (y=0;y<6;y++){
for (x=0;x < 6; x++) {
Button button = new Button(this); //创建Button对象
number=grid_c0[x][y]; //按照两个for循环的序列对数组grid_c0取值(x代表grid_c0对应的行数,y代表grid_c0对应的列数)
string0=String.valueOf(number);
button.setText(string0); //将number由整形变量转化为字符串,然后把它设置为button显示的文字
button.setTextColor(Color.WHITE);
button.setTextSize(75);
button.setComponentSize(160, 160);
//定义按钮的尺寸,按钮内文字的大小和颜色
button.setContentPosition(65+160* x, 230+160*y);
//定义按钮的位置,设位置为T,那么T是关于x和y的函数
if (number==0) { //判断number是否为0
button.setText("");
button.setBackground(element0);
button.setTextColor(Color.BLACK);
//如果是0,button将不显示任何文字,并且使用element0作为button的背景元素
}else{
button.setBackground(element3);
//如果不是0,button显示文字,并且使用element3作为button的背景元素
}
layout1.addComponent(button); //将button组件加入到坐标布局中
}
}
这段代码看起来稍微有点复杂,但只要理解好代码各层的逻辑关系,理解起来还是不费劲的。首先,我们设置了两个for循环,可以看出,以y为变量的for循环嵌套着以x为变量的for循环,这意味着,变量x每完成一次0到5循环,变量y的值才加1,于是这两个for循环会共同生成36个Button组件。
每生成一个Button组件时,系统都会根据这个组件在两个for循环中对应的x和y值,对grid_c0进行取值,以及确定这个Button组件的坐标。这样以后,网格区域每行每列的数字就能与grid_c0每行每列的数字对应起来(也就是跟数独题目对应起来)。
接着,我们还加入了一个判断条件,如果这个Button组件对grid_c0取到的数字为0,那么它将作为待用户填入数字的白色空白网格;如果这个Button组件对grid_c0取到的数字不是0(设其为t),那么它将作为用于提示的蓝色网格(这个网格将显示数字t)。
最后,我们再加上如下代码:
setUIContent(layout1);
这样以后,我们之前所创建的坐标布局对象layout1就被成功设置为GameAbilitySlice的UI框架了。
如果想查看设计的UI效果,我们可以打开MainAbility,把setMainRoute方法内的InitialAbilitySlice修改为GameAbilitySlice(这样就可以修改应用默认显示的页面)。当我们打开模拟机时,我们看到的第一个页面就是GameAbilitySlice了。
效果图如下:
显然,图中网格区域中数字的分布与数组grid_c0的矩阵的数字排布一致,只不过,网格区域中的白色格子在矩阵中用数字0表示。
0 1 6 5 0 3
0 0 2 0 6 1
0 2 3 0 4 0
0 4 0 2 3 5
1 0 0 3 5 0
0 0 5 6 0 4
结尾
本期的内容就先分享到这里,更多关于数独小游戏项目精彩的内容我将在下期继续为大家揭晓。
楼主是学了数独才这么优秀的吗?
优秀!
所以程序写得好,数学一定要很强吧
最打动我的是这个页面,看着真的太舒服了
emm,这个不好说,但写程序是要用到数学思维的
数独小游戏可可可,期待下期。
怎么我效果出不来
这个已经是远古代码了,Java已经被弃用了