手表游戲—黑白翻棋 之 學(xué)習(xí)筆記(前篇)
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
前言
去年我們木棉花組織發(fā)過一篇文章“HarmonyOS手表游戲——黑白翻棋”,本文是我對(duì)該文章的一個(gè)學(xué)習(xí)筆記,隨著IDE的升級(jí),一些代碼也需要作修改。以下是我的學(xué)習(xí)筆記及部分代碼的修改O(∩_∩)O
源代碼請(qǐng)移步至→原文章地址
概述
正文內(nèi)容只展示部分代碼,完整代碼可以下載附件(附件1是源代碼的代碼更新)。效果圖如下:


正文
1.創(chuàng)建一個(gè)空白的工程
DevEco Studio下載安裝成功后,打開DevEco Studio,點(diǎn)擊左上角的File,點(diǎn)擊New,再選擇New Project,選擇Empty Ability(JS),然后點(diǎn)擊Next,給項(xiàng)目命名WatchGame_BW,選擇設(shè)備類型Wearable,最后點(diǎn)擊Finish。

2.界面布局
通過效果圖可見,初始布局分三個(gè)部分,由上至下分別是文本框、棋盤(畫布組件)、按鈕;游戲成功的布局有四個(gè)部分:文本框、棋盤(畫布組件)、游戲成功界面、按鈕。(完整代碼及解釋可以去看原文章)
這里記幾個(gè)小要點(diǎn):
1.當(dāng)前步數(shù)顯示的是一個(gè)動(dòng)態(tài)的值,不是一個(gè)固定的值,這里以動(dòng)態(tài)變量currentSteps來顯示數(shù)據(jù)
2.游戲成功的文本框是顯示在畫布組件之上的(覆蓋),而不是在畫布組件的下方。該實(shí)現(xiàn)可通過添加一個(gè)堆疊容器stack,將游戲成功的文本組件放在畫布組件之后
3.“游戲成功”的顯示在初始時(shí)不會(huì)顯示,所以要設(shè)置屬性show,對(duì)應(yīng)設(shè)一個(gè)布爾型變量isShow,并令isShow的初始值為假,游戲成功時(shí)其值為真,當(dāng)為真時(shí)就可以顯示了
- <div class="container">
- <text class="steps">
- 當(dāng)前步數(shù):{{currentSteps}}
- </text>
- <stack class="stack">
- <canvas class="canvas" ref="canvas"></canvas>
- <div class="subcontainer" show="{{isShow}}">
- <text class="gameover">
- 游戲成功
- </text>
- </div>
- </stack>
- <input type="button" value="重新開始" class="bit" onclick="restartGame"/>
- </div>
相應(yīng)的組件大小顏色等屬性設(shè)置在entry>src>main>js>default>pages.index>index.css文件里通過class設(shè)定的名稱來去設(shè)置,代碼如下:
- .container {
- flex-direction: column;
- justify-content: center;
- align-items: center;
- width:240px;
- height:240px;
- }
- .steps {
- font-size: 10px;
- text-align:center;
- width:100px;
- height:18px;
- letter-spacing:0px;
- margin-top:5px;
- }
- .canvas{
- width:160px;
- height:160px;
- background-color: #BBADA0;
- }
- .bit {
- width: 75px;
- height: 15px;
- background-color: #AD9D8F;
- font-size: 10px;
- margin-top: 5px;
- }
- .stack{
- width: 160px;
- height: 160px;
- margin-top: 5px;
- }
- .subcontainer{
- left: 25px;
- top: 47.5px;
- width: 110px;
- height: 65px;
- justify-content: center;
- align-content: center;
- background-color: #E9C2A6;
- }
- .gameover{
- font-size: 19px;
- color:black;
- }
代碼更新部分:組件大小的數(shù)據(jù)全部都在原文章源代碼的基礎(chǔ)上減半再作微調(diào),即原文章的數(shù)據(jù)不適用,以上代碼是我調(diào)整修改后的
3.實(shí)現(xiàn)色塊的翻轉(zhuǎn)
要先在運(yùn)動(dòng)手表上生成一個(gè)7*7的棋盤,并且點(diǎn)擊棋盤中任一色塊,其上下左右四個(gè)色塊也會(huì)跟著一起變色(在邊緣的色塊則只會(huì)改變其中若干個(gè)色塊的顏色)
原文章的實(shí)現(xiàn)方法是給這49個(gè)色塊分別添加一個(gè)按鈕,并分別添加點(diǎn)擊事件。
布局方面如上所述,色塊(按鈕)是顯示在棋盤(畫布)之上,而游戲成功界面是顯示在色塊(按鈕)及畫布之上,因此stack里的順序應(yīng)該是canvas、button、gameover;且按鈕的相關(guān)大小間距的數(shù)據(jù)也要如上“代碼更新部分”一樣作修改,代碼(修改的部分)如下:
- .bitgrid1{
- left:2.5px;
- top:2.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent
- }
- .bitgrid2{
- left:25px;
- top:2.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent
- }
- .bitgrid3{
- left:47.5px;
- top:2.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent
- }
- .bitgrid4{
- left:70px;
- top:2.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent
- }
- .bitgrid5{
- left:92.5px;
- top:2.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent
- }
- .bitgrid6{
- left:115px;
- top:2.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent
- }
- .bitgrid7{
- left:137.5px;
- top:2.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent
- }
- .bitgrid8{
- left:2.5px;
- top:25px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid9{
- left:25px;
- top:25px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid10{
- left:47.5px;
- top:25px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid11{
- left:70px;
- top:25px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid12{
- left:92.5px;
- top:25px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid13{
- left:115px;
- top:25px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid14{
- left:137.5px;
- top:25px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid15{
- left:2.5px;
- top:47.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid16{
- left:25px;
- top:47.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid17{
- left:47.5px;
- top:47.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid18{
- left:70px;
- top:47.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid19{
- left:92.5px;
- top:47.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid20{
- left:115px;
- top:47.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid21{
- left:137.5px;
- top:47.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid22{
- left:2.5px;
- top:70px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid23{
- left:25px;
- top:70px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid24{
- left:47.5px;
- top:70px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid25{
- left:70px;
- top:70px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid26{
- left:92.5px;
- top:70px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid27{
- left:115px;
- top:70px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid28{
- left:137.5px;
- top:70px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid29{
- left:2.5px;
- top: 92.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid30{
- left:25px;
- top:92.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid31{
- left:47.5px;
- top:92.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid32{
- left:70px;
- top:92.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid33{
- left:92.5px;
- top:92.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid34{
- left:115px;
- top:92.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid35{
- left:137.5px;
- top:92.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid36{
- left:2.5px;
- top:115px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid37{
- left:25px;
- top:115px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid38{
- left:47.5px;
- top:115px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid39{
- left:70px;
- top:115px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid40{
- left:92.5px;
- top:115px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid41{
- left:115px;
- top:115px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid42{
- left:137.5px;
- top:115px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid43{
- left:2.5px;
- top:137.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid44{
- left:25px;
- top:137.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid45{
- left:47.5px;
- top:137.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid46{
- left:70px;
- top:137.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid47{
- left:92.5px;
- top:137.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid48{
- left:115px;
- top:137.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
- .bitgrid49{
- left:137.5px;
- top:137.5px;
- width:20px;
- height:20px;
- border-color:transparent;
- background-color:transparent;
- }
然后在index.js文件里用一個(gè)7*7的數(shù)組表示色塊,其中0表示白色,1代表黑色,這樣我們就能定義一個(gè)用0和1表示鍵,顏色表示值的字典COLORS,并且定義全局常量邊長(zhǎng)SIDELEN為20,間距MARGIN為2.5,定義一個(gè)全局變量的二維數(shù)組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=20;
- const MARGIN=2.5;
- const COLORS = {
- "0": "#FFFFFF",
- "1": "#000000"
- }
設(shè)置色塊的點(diǎn)擊事件
要點(diǎn):點(diǎn)擊時(shí)對(duì)應(yīng)獲取該方塊的位置(例如該方塊時(shí)第3行第4個(gè),則坐標(biāo)為(2,3)),并將該坐標(biāo)傳給函數(shù)changeOneGrids,去判斷該方塊上下左右是否有方塊,并調(diào)用函數(shù)change變換其數(shù)組的值——若0則變?yōu)?,若1則變?yōu)?
- change(x,y){
- if(this.isShow==false){
- if(grids[x][y] == 0){
- grids[x][y] = 1;
- }else{
- grids[x][y] = 0;
- }
- }
- },
- 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);
- }
- }
最后調(diào)用函數(shù)drawgrids去“上色”
- drawGrids(){
- context=this.$refs.canvas.getContext('2d');
- 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);
- }
- }
- },
4.實(shí)現(xiàn)題目的隨機(jī)生成
隨機(jī)生成一個(gè)色塊被打亂的7x7的棋盤,這里是在原來全白的棋盤上隨機(jī)生成20個(gè)黑色塊。
要點(diǎn):把二維數(shù)組的下標(biāo)放進(jìn)一個(gè)列表中,Math.random()函數(shù)是隨機(jī)[0,1)內(nèi)的小數(shù),Math.floor(x)為得出小于或等于x的最大整數(shù),每次隨機(jī)生成一個(gè)數(shù)后,讀取剛才的列表對(duì)應(yīng)的下標(biāo),即獲得一個(gè)在7x7內(nèi)的隨機(jī)的坐標(biāo),調(diào)用函數(shù)changeOneGrids(x,y)
- 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);
- }
- }
5.游戲結(jié)束
當(dāng)該7x7數(shù)組的值全為1時(shí)游戲成功,此時(shí)isShow的值為真,色塊的點(diǎn)擊事件就不起效(change函數(shù)里加個(gè)對(duì)isShow的真假判斷)
- 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函數(shù)里調(diào)用gameover函數(shù);同時(shí),隨著每一次點(diǎn)擊,都會(huì)調(diào)用changeOneGrids函數(shù),所以步數(shù)的增加可以直接在每次changeOneGrids函數(shù)被調(diào)用時(shí)累加
- if(this.isShow==false){
- this.currentSteps+=1;;
- }
- if(this.gameover()){
- this.isShow=true;
- }
6.重新開始
最后編寫重新按鈕對(duì)應(yīng)的函數(shù)restartGame(),作用是是二維數(shù)組、isShow和當(dāng)前步數(shù)全部置為初始化界面
- restartGame(){
- this.initGrids();
- this.drawGrids();
- this.isShow = false;
- this.currentSteps = 0;
- }
修改的說明
1.畫布組件的getContext不支持在onInit和onReady中進(jìn)行調(diào)用,因此我改在drawGrids中調(diào)用,然后再在onShow中調(diào)用drawGrids
2.隨機(jī)生成打亂的色塊時(shí),會(huì)調(diào)用changeOneGrids函數(shù),此時(shí)會(huì)增加步數(shù)20
- data: {
- currentSteps: -20,
- }
3.同1,色塊的隨機(jī)生成函數(shù)initGrids也放在onShow中調(diào)用
結(jié)語(yǔ)
以上是我的初步學(xué)習(xí)筆記啦,我修改過的源代碼會(huì)上傳到附件,更多詳細(xì)的注解步驟可去看原文章。該學(xué)習(xí)筆記還有后續(xù)哦,后續(xù)是對(duì)其中一些功能實(shí)現(xiàn)采用另一種算法來實(shí)現(xiàn),代碼會(huì)在該篇的基礎(chǔ)上再作修改,并且還會(huì)對(duì)相關(guān)知識(shí)注解作一個(gè)小分享,敬請(qǐng)期待(●ˇ∀ˇ●)
文章相關(guān)附件可以點(diǎn)擊下面的原文鏈接前往下載
https://harmonyos.51cto.com/resource/1222
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)