#2020征文-手表#深鸿会深大小组:HarmonyOS手表游戏——黑白翻棋 原创 精华
前言
此次是深鸿会深大小组(Zzt_01-23)学习完HarmonyOS后,自行开发的第一个demo——黑白翻棋,详细讲述了黑白翻棋的编写思路,内含详细解释,同时也欢迎与各位感兴趣的读者一起学习HarmonyOS开发,相互交流、共同进步。
概述
本个demo将从零开始完成鸿蒙小游戏APP在可穿戴设备上的编译,此处以运动手表为例,在项目中我们所使用到的软件为DevEco Studio,下载地址为:DevEco Studio下载,在项目中我们要实现的内容为黑白翻棋APP的开发。
- 在初始界面中显示7*7的棋盘,棋盘中黑白色块为随意打乱的,棋盘上面显示游戏翻转的次数,棋盘下方显示一个“重新开始”的按钮,为用户提供重新开始改游戏。
- 点击7*7棋盘中任一色块,其上下左右四个色块也会跟着一起变色(在边缘的色块则只会改变其中若干个色块的颜色),棋盘上方的当前步数则会相应依次增加。
- 经过若干次点击后,当所有的色块都为白色时,则会弹出游戏成功界面,此时再点击棋盘,不会有任何变化,点击“重新开始”的按钮时则会重新返回步骤1界面所示。
正文
创建项目文件
DevEco Studio下载成功后,点击左上角的File,点击New,再选择New Project,选择Lite Wearable选项,选择默认的模板,然后选择保存路径,将文件命名为MyGame(文件名不能出现中文或者特殊字符,否则将无法成功创建项目文件),如图所示。
主要编写的文件为index.css、index.hml和index.js,打开路径如图所示,index.hml用于描述页面中包含哪些组件,index.css用于描述页面中的组件都长什么样,index.js用于描述页面中的组件是如何进行交互的。
实现开始界面的布局
首先我们要先在运动手表上画出一个7*7的棋盘,色块颜色先设定为全是白色,棋盘上方显示“当前步数:0”,棋盘下方有一个“重新开始”的按钮,如图所示:
- 首先在index.hml文件中创建一个基础容器div类名为container,在此容器中间添加一个文字组件text类名为steps,并且写上显示的固定部分”当前步数:”,为动态变换部分赋予一个名为currentSteps的变量,再添加一个画布组件canvas类名为canvas,增加一个引用属性ref,以便在此画布上画出7*7表格,最后添加一个普通按钮,类名为bit,并赋值“重新开始”
<div class="container" > <text class="steps"> 当前步数:{{currentSteps}} </text> <canvas class="canvas" ref="canvas" ></canvas> <input type="button" value="重新开始" class="bit" /> </div>
- 在index.css编写刚才添加组件的样式,首先编写container的样式,flex-direction为容器主轴方向,选择column(垂直方向从上到下),justify-content为容器当前行的主轴对齐格式,选择center(项目位于容器的中心),align-items为容器当前行的交叉轴对齐格式,选择center(元素在交叉轴居中),width、height分别为容器以像素为单位的宽度和高度,都设定为450px;编写steps的样式,font-size为设置文本的尺寸,设定为18px,text-align为设置文本的文本对齐方式,选择center(文本居中对齐),width、height分别设定为300px和20px,letter-spacing为设置文本的字符间距,设定为0px,margin-top为设置上外边距,设定为10px;编写canvas的样式,width、height都设定为320px,background-color为设置背景颜色,设定为#BBADA0;编写bit的样式,width、height分别设定为150px和30px,background-color设定为#AD9D8F,font-size设定为24px,margin-top设定为10px
.container { flex-direction: column; justify-content: center; align-items: center; width:450px; height:450px; } .steps { font-size: 18px; text-align:center; width:300px; height:20px; letter-spacing:0px; margin-top:10px; } .canvas{ width:320px; height:320px; background-color: #BBADA0; } .bit{ width:150px; height:30px; background-color:#AD9D8F; font-size:24px; margin-top:10px; }
- 在index.js编写描述页面中的组件是如何进行交互的,首先在data函数中为当前步数赋值为0
data: { currentSteps: 0, }
在文件开头定义一个全局变量量context,创建一个onReady()函数,用于定义2d绘画工具
var context; onReady(){ context=this.$refs.canvas.getContext('2d'); }
用0表示白色,1代表黑色,这样我们就能定义一个用0和1表示键,颜色表示值的字典COLORS,并且定义全局常量边长SIDELEN为40,间距MARGIN为5,定义一个全局变量的二维数组grids,其中的值全为0
var grids=[[0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]; const SIDELEN=40; const MARGIN=5; const COLORS = { "0": "#FFFFFF", "1": "#000000" }
创建drawGrids()函数,先将grids的值利用toString()函数全部转化为字符串,fillStyle表社画图的背景颜色,引用字典即可,fillRect表示画矩形的大小,其中有四个参数,第一个参数指定矩形左上角的x坐标,第二参数指定矩形左上角的y坐标,第三个参数指定矩形的高度,第四个参数指定矩形的宽度,最后创建onShow()调用drawGrids()函数即可
onShow(){ this.drawGrids(); }, drawGrids(){ for (let row = 0 ;row < 7 ;row++){ for (let column = 0; column < 7;column++){ let gridStr = grids[row][column].toString(); context.fillStyle = COLORS[gridStr]; let leftTopX = column * (MARGIN + SIDELEN) + MARGIN; let leftTopY = row * (MARGIN + SIDELEN) + MARGIN; context.fillRect(leftTopX, leftTopY, SIDELEN, SIDELEN); } } }
运行即可得出开始界面布局了。
实现题目的随机生成和色块的翻转
其次我们要先在运动手表上随机生成一个色块被打乱的7*7的棋盘,并且点击棋盘中任一色块,其上下左右四个色块也会跟着一起变色(在边缘的色块则只会改变其中若干个色块的颜色),棋盘上方的当前步数则会相应依次增加,如图所示:
- 为了使点击任意一个色块时能得到其对应的二维数组的下标,我们需要给每个色块添加一个按钮button,并增加一个点击事件click,分别给这些按钮设定一个类名和点击按钮所调用的函数然后为了使按钮显示在棋盘格子的上方,需要添加一个栈stack类名设定位stack,使画布先进栈,按钮后进栈,这样就能达到预期效果了,index.hml代码如下:
<div class="container" > <text class="steps"> 当前步数:{{currentSteps}} </text> <stack class="stack"> <canvas class="canvas" ref="canvas" ></canvas> <input type="button" class="bitgrid1" onclick="getgrid1"/> <input type="button" class="bitgrid2" onclick="getgrid2"/> <input type="button" class="bitgrid3" onclick="getgrid3"/> <input type="button" class="bitgrid4" onclick="getgrid4"/> <input type="button" class="bitgrid5" onclick="getgrid5"/> <input type="button" class="bitgrid6" onclick="getgrid6"/> <input type="button" class="bitgrid7" onclick="getgrid7"/> <input type="button" class="bitgrid8" onclick="getgrid8"/> <input type="button" class="bitgrid9" onclick="getgrid9"/> <input type="button" class="bitgrid10" onclick="getgrid10"/> <input type="button" class="bitgrid11" onclick="getgrid11"/> <input type="button" class="bitgrid12" onclick="getgrid12"/> <input type="button" class="bitgrid13" onclick="getgrid13"/> <input type="button" class="bitgrid14" onclick="getgrid14"/> <input type="button" class="bitgrid15" onclick="getgrid15"/> <input type="button" class="bitgrid16" onclick="getgrid16"/> <input type="button" class="bitgrid17" onclick="getgrid17"/> <input type="button" class="bitgrid18" onclick="getgrid18"/> <input type="button" class="bitgrid19" onclick="getgrid19"/> <input type="button" class="bitgrid20" onclick="getgrid20"/> <input type="button" class="bitgrid21" onclick="getgrid21"/> <input type="button" class="bitgrid22" onclick="getgrid22"/> <input type="button" class="bitgrid23" onclick="getgrid23"/> <input type="button" class="bitgrid24" onclick="getgrid24"/> <input type="button" class="bitgrid25" onclick="getgrid25"/> <input type="button" class="bitgrid26" onclick="getgrid26"/> <input type="button" class="bitgrid27" onclick="getgrid27"/> <input type="button" class="bitgrid28" onclick="getgrid28"/> <input type="button" class="bitgrid29" onclick="getgrid29"/> <input type="button" class="bitgrid30" onclick="getgrid30"/> <input type="button" class="bitgrid31" onclick="getgrid31"/> <input type="button" class="bitgrid32" onclick="getgrid32"/> <input type="button" class="bitgrid33" onclick="getgrid33"/> <input type="button" class="bitgrid34" onclick="getgrid34"/> <input type="button" class="bitgrid35" onclick="getgrid35"/> <input type="button" class="bitgrid36" onclick="getgrid36"/> <input type="button" class="bitgrid37" onclick="getgrid37"/> <input type="button" class="bitgrid38" onclick="getgrid38"/> <input type="button" class="bitgrid39" onclick="getgrid39"/> <input type="button" class="bitgrid40" onclick="getgrid40"/> <input type="button" class="bitgrid41" onclick="getgrid41"/> <input type="button" class="bitgrid42" onclick="getgrid42"/> <input type="button" class="bitgrid43" onclick="getgrid43"/> <input type="button" class="bitgrid44" onclick="getgrid44"/> <input type="button" class="bitgrid45" onclick="getgrid45"/> <input type="button" class="bitgrid46" onclick="getgrid46"/> <input type="button" class="bitgrid47" onclick="getgrid47"/> <input type="button" class="bitgrid48" onclick="getgrid48"/> <input type="button" class="bitgrid49" onclick="getgrid49"/> </stack> <input type="button" value="重新开始" class="bit" /> </div>
2. 编写stack的样式,width、height都设定为320px,margin-top设定为10px;分别编写每个按钮的样式,left为指示距边界框左上角的以像素为单位的水平坐标,top为指示距边界框左上角的以像素为单位的垂直坐标,border-color为设置边框颜色,transparent指透明颜色
.stack{ width: 320px; height: 320px; margin-top: 10px; } .bitgrid1{ left:5px; top:5px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid2{ left:50px; top:5px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid3{ left:95px; top:5px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid4{ left:140px; top:5px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid5{ left:185px; top:5px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid6{ left:230px; top:5px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid7{ left:275px; top:5px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid8{ left:5px; top:50px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid9{ left:50px; top:50px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid10{ left:95px; top:50px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid11{ left:140px; top:50px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid12{ left:185px; top:50px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid13{ left:230px; top:50px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid14{ left:275px; top:50px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid15{ left:5px; top:95px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid16{ left:50px; top:95px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid17{ left:95px; top:95px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid18{ left:140px; top:95px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid19{ left:185px; top:95px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid20{ left:230px; top:95px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid21{ left:275px; top:95px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid22{ left:5px; top:140px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid23{ left:50px; top:140px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid24{ left:95px; top:140px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid25{ left:140px; top:140px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid26{ left:185px; top:140px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid27{ left:230px; top:140px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid28{ left:275px; top:140px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid29{ left:5px; top:185px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid30{ left:50px; top:185px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid31{ left:95px; top:185px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid32{ left:140px; top:185px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid33{ left:185px; top:185px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid34{ left:230px; top:185px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid35{ left:275px; top:185px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid36{ left:5px; top:230px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid37{ left:50px; top:230px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid38{ left:95px; top:230px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid39{ left:140px; top:230px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid40{ left:185px; top:230px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid41{ left:230px; top:230px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid42{ left:275px; top:230px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid43{ left:5px; top:275px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid44{ left:50px; top:275px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid45{ left:95px; top:275px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid46{ left:140px; top:275px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid47{ left:185px; top:275px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid48{ left:230px; top:275px; width:40px; height:40px; border-color:transparent; background-color:transparent; } .bitgrid49{ left:275px; top:275px; width:40px; height:40px; border-color:transparent; background-color:transparent; }
3. 先增加一个函数change(x,y),接受二维数组的下标,用来改变二维数字的值,当isShow为false才使二维数组的值发生变化,这样就能达到当游戏成功时再点击色块时颜色不再发生变化,如果值为0 则改为1,如果值为1则改为0,这样对应的色块颜色也能跟着发生变化
change(x,y){ if(this.isShow==false){ if(grids[x][y] == 0){ grids[x][y] = 1; }else{ grids[x][y] = 0; } } }
之后增加一个函数changeOneGrids(x,y),接受二维数组的下标,调用刚才编写的函数change(x,y),改变其上下左右四个色块对应的二维数组的值,并且调用函数drawGrids()重新画图实现颜色的变化,当isShow为false才使currentSteps加1,这样就能达到当游戏成功时再点击色块时currentSteps不再发生变化
changeOneGrids(x,y){ if(x>-1 && y>-1 && x<7 && y<7){ this.change(x,y); } if(x+1>-1 && y>-1 && x+1<7 && y<7){ this.change(x+1,y); } if(x-1>-1 && y>-1 && x-1<7 && y<7){ this.change(x-1,y); } if(x>-1 && y+1>-1 && x<7 && y+1<7){ this.change(x,y+1); } if(x>-1 && y-1>-1 && x<7 && y-1<7){ this.change(x,y-1); } this.drawGrids(); if(this.isShow==false){ this.currentSteps+=1;; } }
再编写49个按钮对应的49个函数,作用是读取当前二维数组位置的下标,并且调用函数changeOneGrids(x,y)
getgrid1(){ this.changeOneGrids(0,0); }, getgrid2(){ this.changeOneGrids(0,1); }, getgrid3(){ this.changeOneGrids(0,2); }, getgrid4(){ this.changeOneGrids(0,3); }, getgrid5(){ this.changeOneGrids(0,4); }, getgrid6(){ this.changeOneGrids(0,5); }, getgrid7(){ this.changeOneGrids(0,6); }, getgrid8(){ this.changeOneGrids(1,0); }, getgrid9(){ this.changeOneGrids(1,1); }, getgrid10(){ this.changeOneGrids(1,2); }, getgrid11(){ this.changeOneGrids(1,3); }, getgrid12(){ this.changeOneGrids(1,4); }, getgrid13(){ this.changeOneGrids(1,5); }, getgrid14(){ this.changeOneGrids(1,6); }, getgrid15(){ this.changeOneGrids(2,0); }, getgrid16(){ this.changeOneGrids(2,1); }, getgrid17(){ this.changeOneGrids(2,2); }, getgrid18(){ this.changeOneGrids(2,3); }, getgrid19(){ this.changeOneGrids(2,4); }, getgrid20(){ this.changeOneGrids(2,5); }, getgrid21(){ this.changeOneGrids(2,6); }, getgrid22(){ this.changeOneGrids(3,0); }, getgrid23(){ this.changeOneGrids(3,1); }, getgrid24(){ this.changeOneGrids(3,2); }, getgrid25(){ this.changeOneGrids(3,3); }, getgrid26(){ this.changeOneGrids(3,4); }, getgrid27(){ this.changeOneGrids(3,5); }, getgrid28(){ this.changeOneGrids(3,6); }, getgrid29(){ this.changeOneGrids(4,0); }, getgrid30(){ this.changeOneGrids(4,1); }, getgrid31(){ this.changeOneGrids(4,2); }, getgrid32(){ this.changeOneGrids(4,3); }, getgrid33(){ this.changeOneGrids(4,4); }, getgrid34(){ this.changeOneGrids(4,5); }, getgrid35(){ this.changeOneGrids(4,6); }, getgrid36(){ this.changeOneGrids(5,0); }, getgrid37(){ this.changeOneGrids(5,1); }, getgrid38(){ this.changeOneGrids(5,2); }, getgrid39(){ this.changeOneGrids(5,3); }, getgrid40(){ this.changeOneGrids(5,4); }, getgrid41(){ this.changeOneGrids(5,5); }, getgrid42(){ this.changeOneGrids(5,6); }, getgrid43(){ this.changeOneGrids(6,0); }, getgrid44(){ this.changeOneGrids(6,1); }, getgrid45(){ this.changeOneGrids(6,2); }, getgrid46(){ this.changeOneGrids(6,3); }, getgrid47(){ this.changeOneGrids(6,4); }, getgrid48(){ this.changeOneGrids(6,5); }, getgrid49(){ this.changeOneGrids(6,6); }
最后是随机生成一个色块被打乱的7 7的棋盘,首先我们得先把二维数组的下标放进一个列表中,Math.random()函数是随机[0,1)内的小数,Math.floor(x)为得出小于或等于x的最大整数,每次随机生成一个数后,读取刚才的列表对应的下标,调用函数changeOneGrids(x,y),重复此操作若干次,这样就能随机生成一个色块被打乱的7*7的棋盘
initGrids(){ let array = []; for (let row = 0; row < 7; row++) { for (let column = 0; column < 7; column++) { if (grids[row][column] == 0) { array.push([row, column]) } } } for (let i = 0; i < 20; i++){ let randomIndex = Math.floor(Math.random() * array.length); let row = array[randomIndex][0]; let column = array[randomIndex][1]; this.changeOneGrids(row,column); } }
至此,这一部分内容已经全部编写完毕。
实现游戏结束页面
最后我们要实现当色块的颜色全部为白色时弹出游戏成功界面,并使按钮“重新开始”能够重新随机生成随机生成一个色块被打乱的7*7的棋盘,当前步数置为0,如图所示:
1. 首先我们得在栈stack组件中增加一个游戏成功的容器div类名为subcontainer,以isShow控制该容器是否进栈,增加文本组件text,类名gameover,并赋值“游戏成功”,再为重新开始按钮增加一个点击事件click,所调用的函数为restartGame
<div class="subcontainer" show="{{isShow}}">
<text class="gameover">
游戏成功
</text>
</div>
<input type="button" value="重新开始" class="bit" onclick="restartGame"/>
2. 编写刚才增加组件的样式,编写subcontainer的样式和gameover的样式
.subcontainer {
left:50px;
top:95px;
width: 220px;
height: 130px;
justify-content: center;
align-items: center;
background-color: #E9C2A6;
}
.gameover {
font-size: 38px;
color: black;
}
3. 首先给isShow赋值false,将开头的全局变量grids赋值删除,增加一个函数给grids赋值,并调用函数initGrids()
var grids;
data: {
currentSteps: 0,
isShow: false
}
onInit() {
grids=[[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]];
this.initGrids();
}
增加一个函数gameover(),当棋盘所有色块颜色为白色时返回true,否则返回false,即当二维数组的值全为0时返回true,否则返回false
gameover(){
for (let row = 0 ;row < 7 ;row++){
for (let column = 0; column < 7;column++){
if (grids[row][column]==1){
return false;
}
}
}
return true;
}
在函数changeOneGrids(x,y)中添加当函数gameover()为true时,将isShow赋值为true,使游戏成功界面显示在最上方,当isShow为false时,步数增加1
changeOneGrids(x,y){
if(x>-1 && y>-1 && x<7 && y<7){
this.change(x,y);
}
if(x+1>-1 && y>-1 && x+1<7 && y<7){
this.change(x+1,y);
}
if(x-1>-1 && y>-1 && x-1<7 && y<7){
this.change(x-1,y);
}
if(x>-1 && y+1>-1 && x<7 && y+1<7){
this.change(x,y+1);
}
if(x>-1 && y-1>-1 && x<7 && y-1<7){
this.change(x,y-1);
}
this.drawGrids();
if(this.isShow==false){
this.currentSteps+=1;;
}
if(this.gameover()){
this.isShow=true;
}
}
最后编写重新按钮对应的函数restartGame(),作用是是二维数组、isShow和当前步数全部置为初始化界面
restartGame(){
this.onInit();
this.drawGrids();
this.isShow = false;
this.currentSteps = 0;
}
至此,整个demo全部完成了。
结语
以上就是黑白翻棋小游戏代码的主要编写思路以及代码,源码将放在附件中,欢迎大家下载,感兴趣的读者可以自行跟着编写学习,相信你们也能够完成的。更多深鸿会深大小组学习项目可以查看荔园Harmony,也欢迎各位关注我的专栏【荔园Harmony基地】:荔园Harmony基地,鸿蒙开发者的学习分享,更多精彩内容会持续更新,如果有遇到什么问题,或者查找出其中的错误之处,或者能够优化代码,也欢迎评论区留言讨论,让我们一起进步!
楼主,传原图吧。
谢谢提醒,马上修改
惊了 社区又出现神仙帖了👍
不错哟,lz可以更改个记得住的昵称哦~
好建议\(^o^)/~
666666
好棒好棒好棒
👍👍👍