人生倒计时
-
今日已经过去小时
-
这周已经过去天
-
本月已经过去天
-
今年已经过去个月
从零开发HarmonyOS(鸿蒙)运动手表小游戏—数字华容道
本个demo将从零基础开始完成鸿蒙小游戏APP在可穿戴设备上的编译,此处以运动手表为例,在项目中我们所使用到的软件为DevEcoStudio,下载地址为:DevEcoStudio下载、DevEcoStudio安装教程,在项目中我们要实现的内容为数字华容道APP的开发。
在初始界面中显示4*4的方阵,方阵中分布有随意打乱的1至15的数字和一个空白方格,方阵上方增加一个计时器,显示游戏进行的时间,单位为秒,方阵下方显示一个“重新开始”的按钮,为用户提供重新开始游戏的机会。
向上、下、左、右任一方向滑动,空白方格周围对应位置的方格便会随之向对应的方向移动一格,计时器也会显示游戏开始到当前的时间。
正文创建项目主要编写的文件为、和,打开路径如图所示,用于描述页面中包含哪些组件,用于描述页面中的组件都长什么样,用于描述页面中的组件是如何进行交互的。
实现开始界面的布局首先,我们要先画出一个4*4的方阵,方阵中按照顺序显示1至15的数字,方阵上方显示“当前秒数:0”,方阵下方有一个“重新开始”的按钮。
1.在中添加相应的页面组件:
首先创建一个基础容器div类名为container,用于盛装所有的其他组件
divclass="container"/div
然后在此基础容器中添加一个文字组件text类名为seconds,且注明显示的固定部分“当前秒数:”,为动态变换部分赋予一个名为currentSteps的变量,用于动态显示游戏进行的秒数
textclass="seconds"当前秒数:{{currentSeconds}}/text再添加一个画布组件canvas类名为canvas,增加一个引用属性ref,用来指定指向子元素或子组件的引用信息,该引用将注册到父组件的$refs属性对象上,以便在此画布上画出4*4的方阵
canvasclass="canvas"ref="canvas"/canvas
最后添加一个普通按钮组件,类名为bit,并赋值“重新开始”,用于重新开始游戏
inputtype="button"value="重新开始"class="bit"/
至此,文件已经全部编写完毕
divclass="container"textclass="seconds"当前秒数:{{currentSeconds}}/textcanvasclass="canvas"ref="canvas"/canvasinputtype="button"value="重新开始"class="bit"//div2.在中描述刚才添加的页面组件的样式:
首先编写container的样式,flex-direction为容器主轴方向,选择column(垂直方向从上到下),justify-content为容器当前行的主轴对齐格式,选择center(项目位于容器的中心),align-items为容器当前行的交叉轴对齐格式,选择center(元素在交叉轴居中),width、height分别为容器以像素为单位的宽度和高度,都设定为450px
.container{flex-direction:column;justify-content:center;align-items:center;width:450px;height:450px;}然后编写seconds的样式,font-size为设置文本的尺寸,设定为18px,text-align为设置文本的文本对齐方式,选择center(文本居中对齐),width、height分别设定为300px和20px,letter-spacing为设置文本的字符间距,设定为0px,margin-top为设置上外边距,设定为10px
.seconds{font-size:18px;text-align:center;width:300px;height:20px;letter-spacing:0px;margin-top:10px;}再编写canvas的样式,width、height都设定为320px,background-color为设置背景颜色,设定为FFFFFF;}
最后编写bit的样式,width、height分别设定为150px和30px,background-color设定为AD9D8F;font-size:24px;margin-top:10px;}
至此,文件已经全部编写完毕
3.在中描述页面中的组件交互情况:
首先在data中为当前秒数currentSeconds赋值为0
data:{currentSeconds:0,}然后在文件开头定义一个全局变量context,定义一个全局变量的二维数组grids,其中的值为1至15和0,定义全局常量方格的边长SIDELEN为70,方格的间距MARGIN为5,创建一个onReady()函数,用于定义2d绘画工具
vargrids=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,0]];varcontext;constSIDELEN=70;constMARGIN=5;onReady(){context=this.$('2d');}再创建drawGrids()函数,先将grids的值利用toString()函数全部转化为字符串,fillStyle为画图工具context的方格的颜色,方格的背景颜色定义为000000,fillRect为画图工具context的画图矩形的大小,其中有四个参数,第一个参数指定矩形左上角的x坐标,第二个参数指定矩形左上角的y坐标,第三个参数指定矩形的高度,第四个参数指定矩形的宽度。font为为画图工具context的字体大小,定义为30pxHYQiHei-65S,因为要出现一个空白的方格,所以需要添加一个判断语句,当数字为0时不显示数字。fillText为画图工具context的文本字体大小,其中有三个参数,第一个参数为绘制的文本,第二个参数指定文本左上角的x坐标,第三个参数指定文本左上角的y坐标,最后创建onShow()函数,用于调用drawGrids()函数
onShow(){();},drawGrids(){for(letrow=0;row4;row++){for(letcolumn=0;column4;column++){letgridStr=grids[row][column].toString();="000000";letoffsetX=(4-)*(SIDELEN/8);letoffsetY=(SIDELEN-30)/2;(gridStr,leftTopX+offsetX,leftTopY+offsetY);}}}}至此,文件已经全部编写完毕,运行即可得出上述界面布局了
vargrids=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,0]];varcontext;constSIDELEN=70;constMARGIN=5;exportdefault{data:{currentSeconds:0,},onReady(){context=this.$('2d');},onShow(){();},drawGrids(){for(letrow=0;row4;row++){for(letcolumn=0;column4;column++){letgridStr=grids[row][column].toString();="000000";letoffsetX=(4-)*(SIDELEN/8);letoffsetY=(SIDELEN-30)/2;(gridStr,leftTopX+offsetX,leftTopY+offsetY);}}}},}实现数字的随机打乱和方格的移动其次我们要在屏幕上随机生成一个数字被随意打乱的4*4的方阵,并且向任意方向滑动屏幕,空白方格周围对应位置的方格便会随之向对应的方向移动一格
1.在中添加相应的页面组件:
我们需要在画布中添加一个swipe属性,用于响应滑动事件,赋予一个所自动调用的函数swipeGrids
canvasclass="canvas"ref="canvas"onswipe="swipeGrids"/canvas
至此,文件已经全部编写完毕
2.在中描述刚才添加的页面组件的样式:
这一部分不需要添加或修改页面组件的样式
3.在中描述页面中的组件交互情况:
首先我们得先实现方格的移动,创建一个函数changeGrids(direction),接受一个参数direction指示滑动的方向,先找出空白方格所在位置对应的二维数组下标,接着判断参数direction为’left’、‘right’、‘up’或’down’时,对应的方格和空白方格对应的二维数组的数值对调,创建响应滑动事件所自动调用的函数swipeGrids(event),参数为滑动事件,调用函数changeGrids(direction),并传入滑动的方向,最后调用函数drawGrids()
swipeGrids(event){();();},changeGrids(direction){letx;lety;for(letrow=0;row4;row++){for(letcolumn=0;column4;column++){if(grids[row][column]==0){x=row;y=column;break;}}}lettemp;if(direction=='left'(y+1)4){temp=grids[x][y+1];grids[x][y+1]=grids[x][y];grids[x][y]=temp;}elseif(direction=='right'(y-1)-1){temp=grids[x][y-1];grids[x][y-1]=grids[x][y];grids[x][y]=temp;}elseif(direction=='up'(x+1)4){temp=grids[x+1][y];grids[x+1][y]=grids[x][y];grids[x][y]=temp;}elseif(direction=='down'(x-1)-1){temp=grids[x-1][y];grids[x-1][y]=grids[x][y];grids[x][y]=temp;}}然后添加一个函数initGrids(),用于随机打乱排列规则的数字,先创建一个一维数组变量array,赋值为上下左右四个方向"left",“up”,“right”,“down”,()函数是随机[0,1)内的小数,()*4是随机[0,4)内的小数,(x)为得出小于或等于x的最大整数,随机生成一个数字,读取数组array对应的值,调用函数(direction)并将刚才的array对应的值传入,便能移动一次方格,循环此步骤若干次便可随机打乱排列规则的数字,生成一个数字被随意打乱的4*4的方阵
initGrids(){letarray=["left","up","right","down"];for(leti=0;i100;i++){letrandomIndex=(()*4);letdirection=array[randomIndex];(direction);}}最后在函数onShow()中调用函数initGrids()
onShow(){();();}至此,文件已经全部编写完毕,运行即可得出上述界面布局了
实现计时器、重新开始和游戏成功
1.在中添加相应的页面组件:
为了使数字按顺序排列后才显示“游戏成功”界面,需要添加一个栈stack类名设定为stack,使画布先进栈,“游戏成功”后进栈,这样就能达到“游戏成功”界面显示在画布上方了
stackclass="stack"/stack
在栈stack组件中增加一个游戏成功的容器div类名为subcontainer,以isShow控制该容器是否进栈,当isShow为true时才进栈,增加文本组件text,类名gameover,并赋值“游戏成功”
divclass="subcontainer"show="{{isShow}}"textclass="gameover"游戏成功/text/divinputtype="button"value="重新开始"class="bit"onclick="restartGame"/
至此,文件已经全部编写完毕
divclass="container"textclass="seconds"当前秒数:{{currentSeconds}}/textstackclass="stack"canvasclass="canvas"ref="canvas"onswipe="swipeGrids"/canvasdivclass="subcontainer"show="{{isShow}}"textclass="gameover"游戏成功/text/div/stackinputtype="button"value="重新开始"class="bit"onclick="restartGame"//div2.在中描述刚才添加的页面组件的样式:
首先编写stack的样式,width、height都设定为320px,margin-top设定为10px
.stack{width:305px;height:305px;margin-top:10px;}然后编写subcontainer的样式,left为指示距边界框左上角的以像素为单位的水平坐标,top为指示距边界框左上角的以像素为单位的垂直坐标,width、height分别设定为220px和130px,justify-content选择center,align-items选择center,background-color设定为E9C2A6;}
最后编写gameover的样式,font-size设定为38px,color设定为black
.gameover{font-size:38px;color:black;}至此,文件已经全部编写完毕
3.在中描述页面中的组件交互情况:
首先在data函数中给isShow赋值为false,将开头的全局变量grids赋值删除,增加一个函数onInit()给grids赋值,并调用函数initGrids()和()
vargrids;data:{currentSeconds:0,isShow:false},onInit(){grids=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,0]];();();}然后在开头定义一个全局变量timer赋值为null,在函数onShow()中增加一个计时器setInterval(),其中有两个参数,第一个参数为调用的函数,第二个参数为每隔多长时间调用一次函数,单位为毫秒,再定义调用的函数run(),用于每次currentSeconds加1,至此计时器便完成了
vartimer=null;onShow(){();();timer=setInterval(,1000);}run(){+=1;}再在函数中swipeGrids(event)增加判断数字是否有顺序地排列好即判断游戏是否成功,循环判断当前二维数组的数值是否等于有顺序排列好的二维数组的数值即可判断游戏是否成功,当游戏成功时将isShow赋值为true,使游戏成功界面显示在最上方,并且调用函数clearInterval停止计时
swipeGrids(event){();();letoriginalgrids=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,0]];letk=1;for(letrow=0;row4;row++){for(letcolumn=0;column4;column++){if(grids[row][column]!=originalgrids[row][column]){k=0;}}}if(k){clearInterval(timer);=true;}}restartGame(){();=false;timer=null;();=0;}至此,文件已经全部编写完毕,整个demo也全部完成了
心得体会本个demo整体难度不高,涉及的组件或样式都是很常见的,需要掌握栈、按钮、画布、计时器、滑动等组件即可完成编写,组件交互采用二维数组串连整个项目,十分适合刚入门的读者编写与学习,其中组件学习可以前往官方文档查看更详细的介绍:官方文档,较之第一个游戏黑白翻棋,组件虽多了一种,但算法更简单了,代码更优化,可读性更加强,建议读者在学习时可以与第一个游戏黑白翻棋对照一起学习:黑白翻棋。
结语本次项目为博主学习了鸿蒙一些基础后自行编写完成的,感兴趣的读者可以自行跟着本博客编写,相信你们也能够完成的。如果有遇到什么问题,或者查找出其中的错误之处,欢迎留言,本博主也欢迎与各位感兴趣的读者一起学习HarmonyOS(鸿蒙)开发。
源代码如下:
divclass="container"textclass="seconds"当前秒数:{{currentSeconds}}/textstackclass="stack"canvasclass="canvas"ref="canvas"onswipe="swipeGrids"/canvasdivclass="subcontainer"show="{{isShow}}"textclass="gameover"游戏成功/text/div/stackinputtype="button"value="重新开始"class="bit"onclick="restartGame"//div如下:
.container{flex-direction:column;justify-content:center;align-items:center;width:450px;height:450px;}.seconds{font-size:18px;text-align:center;width:300px;height:20px;letter-spacing:0px;margin-top:10px;}.canvas{width:305px;height:305px;background-color:AD9D8F;font-size:24px;margin-top:10px;}.stack{width:305px;height:305px;margin-top:10px;}.subcontainer{left:50px;top:95px;width:220px;height:130px;justify-content:center;align-items:center;background-color:BBADA0";letleftTopX=column*(MARGIN+SIDELEN)+MARGIN;letleftTopY=row*(MARGIN+SIDELEN)+MARGIN;(leftTopX,leftTopY,SIDELEN,SIDELEN);="30pxHYQiHei-65S";if(gridStr!="0"){="#000000";letoffsetX=(4-)*(SIDELEN/8);letoffsetY=(SIDELEN-30)/2;(gridStr,leftTopX+offsetX,leftTopY+offsetY);}}}},run(){+=1;},swipeGrids(event){();();letoriginalgrids=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,0]];letk=1;for(letrow=0;row4;row++){for(letcolumn=0;column4;column++){if(grids[row][column]!=originalgrids[row][column]){k=0;}}}if(k){clearInterval(timer);=true;}},changeGrids(direction){letx;lety;for(letrow=0;row4;row++){for(letcolumn=0;column4;column++){if(grids[row][column]==0){x=row;y=column;break;}}}lettemp;if(direction=='left'(y+1)4){temp=grids[x][y+1];grids[x][y+1]=grids[x][y];grids[x][y]=temp;}elseif(direction=='right'(y-1)-1){temp=grids[x][y-1];grids[x][y-1]=grids[x][y];grids[x][y]=temp;}elseif(direction=='up'(x+1)4){temp=grids[x+1][y];grids[x+1][y]=grids[x][y];grids[x][y]=temp;}elseif(direction=='down'(x-1)-1){temp=grids[x-1][y];grids[x-1][y]=grids[x][y];grids[x][y]=temp;}},restartGame(){();=false;timer=null;();=0;}}







