在DevEco Studio中点击File -> New Project -> [Standard]Empty Ability -> Next,Project type 选择Application,Language选择JS语言,最后点击Finish完成项目创建。
左边是游戏标题和游戏规则,右边是两种游戏模式入口按钮。
<div class="container" onswipe="touchMove">
<div class="textleft">
<text class="title">{{ title }}</text>
<text class="rule">{{ rule }}</text>
</div>
<div class="btnright">
<input class="btn" type="button" value="4 × 4" onclick="playgame(4)"></input>
<input class="btn" type="button" value="5 × 5" onclick="playgame(5)"></input>
</div>
</div>
效果图如上,可以分为三部分
用文本组件显示变量currentSeconds。
<text class="seconds">当前秒数:{{currentSeconds}} s</text>
分别用两个canvas组件显示原图和 n×n 的拼图。其中拼图部分使用stack布局,用于完成游戏时显示弹窗。
<div>
<stack class="stack">
<canvas class="canvas" ref="canvas0" onswipe="swipeGrids"></canvas>
</stack>
<stack class="stack">
<canvas class="canvas" ref="canvas" onswipe="swipeGrids"></canvas>
<div class="subcontainer" show="{{isShow}}">
<text class="gameover">
游戏成功
</text>
</div>
</stack>
</div>
refer() {
ctx0 = this.$refs.canvas0.getContext('2d');
var init = new Image();
init.src = this.img.src
init.onload = function () {
console.log('Image load success');
ctx0.drawImage(init, 0, 0, 360, 360, 0, 0, 240, 240);
};
},
drawGrids() {
context = this.$refs.canvas.getContext('2d');
for (let row = 0; row < this.block; row++) {
for (let column = 0; column < this.block; column++) {
let gridStr = 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 HYQiHei-65S";
if (gridStr != "0") {
context.fillStyle = "#000000";
let offsetX = (3 - gridStr.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轴画图的长度
if(true == this.tip) {
context.fillText(gridStr, 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);
}
}
}
}
},
4个input组件横向排列,分别绑定对应的功能方法。
<div>
<input type="button" value="返回首页" class="btn" onclick="quit"></input>
<input type="button" value="换张图" class="btn" onclick="changeimage"></input>
<input type="button" value="重新开始" class="btn" onclick="restartGame"></input>
<input type="button" value="提示" class="btn" 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 = images[this.index % images.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.run, 1000);
this.refer(); //参照画布,可替换
},
进行一千次上、下、左、右随机滑动,打乱拼图。
initGrids() {
let array=["left","up","right","down"];
for (let i = 0; i < 1000; i++){
let randomIndex = Math.floor(Math.random() * this.block);
let direction = array[randomIndex];
this.changeGrids(direction);
}
},
swipeGrids(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 == '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;
} else 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;
}
}
},
设置提示标识符变量,为true时开启数字提示。
gethelp() {
this.tip = !this.tip;
this.drawGrids();
},
初始化时给每个拼图网格编号,每次滑动操作结束后进行编号比对。
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 = images[this.index % images.length].src;
this.restartGame();
},
项目仓库地址: https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/Entertainment/Jigsaw
1)git下载
git clone https://gitee.com/openharmony-sig/knowledge_demo_temp.git
2)项目导入
打开DevEco Studio,点击File->Open->下载路径/FA/Entertainment/Jigsaw
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。