简单的JS鸿蒙小游戏——拼图(冬奥一起拼)

青春须早为,岂能长少年。这篇文章主要讲述简单的JS鸿蒙小游戏——拼图(冬奥一起拼)相关的知识,希望能为你提供帮助。
春节不停更,此文正在参加「星光计划-春节更帖活动」
前言大家最近看冬奥会了吗,运动员在冰天雪地里驰骋,在赛场上勇夺名次,还有冬奥萌物冰墩墩、雪容融也深受大家的喜爱。虽然不能给大家真的冰墩墩,但可以带大家学习用JS写一个简单的拼图游戏,用拼图的方式重现运动员们的帅气英姿,拼出完整的冰墩墩。
新建工程【简单的JS鸿蒙小游戏——拼图(冬奥一起拼)】在DevEco Studio中点击File -> New Project -> Empty Ability -> Next,Project type 选择Application,Language选择JS语言,API版本这里用的是6,最后点击Finish完成项目创建。
项目结构

简单的JS鸿蒙小游戏——拼图(冬奥一起拼)

文章图片

页面构建 首页
简单的JS鸿蒙小游戏——拼图(冬奥一起拼)

文章图片

  • 设置背景图片:使用通用样式background-image进行背景图片设置。
.container display: flex; flex-direction: column; width: 100%; height: 100%; background-image: url(/common/images/bg.png); background-size: cover;

  • 添加两个游戏模式入口按钮:跳转进入游戏页面,根据传值不同拼图格式也不同。
< div class="container"> < input class="btn" type="button" value="https://www.songbingjia.com/android/4 × 4" onclick="playgame(4)"> < /input> < input class="btn" type="button" value="https://www.songbingjia.com/android/5 × 5" onclick="playgame(5)"> < /input> < /div>

游戏页面
简单的JS鸿蒙小游戏——拼图(冬奥一起拼)

文章图片

  • 顶部计时器:用于显示游戏用时。
< text class="time"> 当前秒数: mytimes< /text>

  • 中间两个画布:左边是参照用的原图;右边是打乱后的拼图和默认隐藏的弹窗。分别用两个canvas组件显示原图和 n×n 的拼图,使用stack布局方便设置游戏完成时显示的弹窗。
< div> < stack class="stack"> < canvas class="canvas" ref="canvas0" onswipe="slide"> < /canvas> < /stack> < stack class="stack"> < canvas class="canvas" ref="canvas" onswipe="slide"> < /canvas> < div class="popup" show="isShow"> < text class="gameover"> 游戏成功< /text> < /div> < /stack> < /div>

  • 底部功能按钮:分别用于返回首页,切换图片,重新开始和开关提示。
< div> < input type="button" class="btn" value="https://www.songbingjia.com/android/返回首页" onclick="quit"> < /input> < input type="button" class="btn" value="https://www.songbingjia.com/android/换张图" onclick="changeimage"> < /input> < input type="button" class="btn" value="https://www.songbingjia.com/android/重新开始" onclick="restartGame"> < /input> < input type="button" class="btn" value="https://www.songbingjia.com/android/提示" onclick="gethelp"> < /input> < /div>

游戏逻辑
  • 首页游戏模式传值跳转,选择游戏模式4×4或5×5
playgame(num) router.replace( uri: "pages/jigsaw/jigsaw", params: block: num, , )

  • 游戏页面网格格式计算:根据页面路由的传值,计算拼图网格的大小及间隙,再进行绘制。
//网格初始化 onInit() CUT_SID = 360 / this.block - (this.block + 1); SIDELEN = 240 / this.block - (this.block + 1); MARGIN = this.block; this.img.src = https://www.songbingjia.com/android/list[this.index % list.length].src; ,//页面显示 onShow() if(4 == this.block) grids=[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 0]]; else grids=[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 0]]; timer = null; this.initGrids(); this.drawGrids(); timer = setInterval(()=> this.mytime += 1; , 1000); this.refer(); //参照画布,可替换 ,

  • 游戏页面网格绘制:使用canvas组件的drawImage方法裁切源图像绘制网格。
//画网格 drawGrids() context = this.$refs.canvas.getContext(2d); for (let row = 0; row < this.block; row++) for (let column = 0; column < this.block; column++) let order = grids[row][column].toString(); context.fillStyle = "#BBADA0"; let leftTopX = column * (MARGIN + SIDELEN) + MARGIN; let leftTopY = row * (MARGIN + SIDELEN) + MARGIN; context.fillRect(leftTopX, leftTopY, SIDELEN, SIDELEN); context.font = "28px"; if (order != "0") context.fillStyle = "#000000"; let offsetX = (3 - order.length) * (SIDELEN / 8); let offsetY = (SIDELEN - 14); context.drawImage(this.img, (CUT_SID + MARGIN) * ((grids[row][column] - 1) % this.block) + MARGIN, //原图img的X轴裁剪起点 (CUT_SID + MARGIN) * (Math.floor((grids[row][column] - 1) / this.block)) + MARGIN, //原图img的Y轴裁剪起点 CUT_SID, CUT_SID, //原图X轴,Y轴方向的裁剪长度 leftTopX, leftTopY, //画布X轴,Y轴画图的起点 SIDELEN, SIDELEN); //画布X轴,Y轴画图的长度 //console.info(JSON.stringify(this.img)); //console.info("拼图——宽:" + this.img.width + ",高:" + this.img.height); if(true == this.tip) context.fillText(order, leftTopX + offsetX, leftTopY + offsetY); else context.fillText("", leftTopX + offsetX, leftTopY + offsetY); else if(true == this.isShow) context.drawImage(this.img, (CUT_SID + MARGIN) * ((Math.pow(this.block, 2) - 1) % this.block) + MARGIN, //原图img的X轴裁剪起点 (CUT_SID + MARGIN) * (Math.floor((Math.pow(this.block, 2) - 1) / this.block)) + MARGIN, //原图img的Y轴裁剪起点 CUT_SID, CUT_SID, //原图X轴,Y轴方向的裁剪长度 leftTopX, leftTopY, //画布X轴,Y轴画图的起点 SIDELEN, SIDELEN); //画布X轴,Y轴画图的长度else context.drawImage(this.img, 0, 0, 0, 0, 0, 0, SIDELEN, SIDELEN); ,

  • 随机打乱拼图:进行一千次上、下、左、右随机滑动,打乱拼图。
//随机上下左右打乱1000次 initGrids() let array=["up","down","left","right"]; for (let i = 0; i < 1000; i++) let randomIndex = Math.floor(Math.random() * this.block); let direction = array[randomIndex]; this.changeGrids(direction); ,

  • 监听滑动事件:根据玩家的滑动方向交换拼图灰块与邻格的位置。
//滑动网格 slide(event) this.changeGrids(event.direction); if(this.gameover()) clearInterval(timer); this.isShow = true; this.tip = false; this.drawGrids(); ,//滑动操作 changeGrids(direction) let x; let y; for (let row = 0; row < this.block; row++) for (let column = 0; column < this.block; column++) if (grids[row][column] == 0) x = row; y = column; break; let temp; if(this.isShow==false) if (direction == up & & (x + 1) < this.block) temp = grids[x + 1][y]; grids[x + 1][y] = grids[x][y]; grids[x][y] = temp; else if (direction == down & & (x - 1) > -1) temp = grids[x - 1][y]; grids[x - 1][y] = grids[x][y]; grids[x][y] = temp; else if (direction == left & & (y + 1) < this.block) temp = grids[x][y + 1]; grids[x][y + 1] = grids[x][y]; grids[x][y] = temp; else if (direction == right & & (y - 1) > -1) temp = grids[x][y - 1]; grids[x][y - 1] = grids[x][y]; grids[x][y] = temp; ,

  • 拼图数字提示:设置提示标识符,为true时开启数字提示。
简单的JS鸿蒙小游戏——拼图(冬奥一起拼)

文章图片

//数字提示开关 gethelp() this.tip = !this.tip; this.drawGrids(); ,

  • 拼图完成判断:当前拼图序列与初始状态相同时即完成拼图。
简单的JS鸿蒙小游戏——拼图(冬奥一起拼)

文章图片

//游戏结束判断 gameover() let originalgrids; if(4 == this.block) originalgrids=[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 0]]; else originalgrids=[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 0]]; for (let row = 0; row < this.block; row++) for (let column = 0; column < this.block; column++) if (grids[row][column] != originalgrids[row][column]) return false; return true; ,

  • 图片切换:改变当前图片序号,用该序号与图片清单长度作求余,循环改变图片的资源路径。
//换张图 changeimage() this.index += 1; this.img.src = https://www.songbingjia.com/android/list[this.index % list.length].src; this.restartGame(); ,

图片导入尺寸要求(360×360像素),将图片放入images文件夹,并在list.js中录入图片信息,图片清单格式如下:
export let list =[index: 0, src: "common/images/0.png", ,//省略中间的若干数据index: 18, src: "common/images/18.png", , ]export default list;

简单的JS鸿蒙小游戏——拼图(冬奥一起拼)

文章图片

结语至此,拼图游戏的设计开发过程全部讲解完毕。希望大家在学习之余适时锻炼,有个健康的好身体,祝我们的奥运健儿一马当先,全员举绩,超越自我,再创辉煌。
附件链接:https://harmonyos.51cto.com/resource/1710
想了解更多关于鸿蒙的内容,请访问:
51CTO和华为官方合作共建的鸿蒙技术社区
https://harmonyos.51cto.com/#bkwz
::: hljs-center
简单的JS鸿蒙小游戏——拼图(冬奥一起拼)

文章图片

:::

    推荐阅读