前言
拼数字小游戏其实是借鉴了很多前辈写的案例,然后自己去动手写了一下。主要是学习使用OpenHarmony开发相关知识,包括一些API需要自己去踩踩坑才行,小游戏其中还有很多不足之处,后面有时间了会尝试做成闯关的类型,包括统计分数做一个排行榜等其他功能。
效果展示
简单演示一下,因为是4*4的,想拼成可能要花费一些时间。
排列成功后的效果是这样的!
实现原理
- 创建一个4*4的表格方阵,将一个空白方格和1到15的数字随意打乱在方阵中,使其随机分布。表格上方放一个定时器,用来记录游戏进行的时间,单位为秒,表格下方放一个“开始游戏”的按钮,点击后开始游戏。
- 单击控制鼠标,在表格方阵上向上、下、左、右随意一个方向进行移动,计时器开始计时,空白方格周围对应位置的方格会随着鼠标移动的方向,向对应的方向移动一格。
- 在进行多次的移动后,所有的数字按照顺序排列完成后,会弹出“你真滴棒!”的提示游戏完成的界面。
使用到的官方API
getContext
getContext(type: ‘2d’, options: ContextAttrOptions): CanvasRendering2dContext。
获取canvas绘图上下文 – 不支持在onInit和onReady中进行调用。
- 参数
参数名 | 参数类型 | 必填 | 描述 |
type | string | 是 | 设置为’2d’,返回值为2D绘制对象,该对象可用于在画布组件上绘制矩形、文本、图片等。 |
options | ContextAttrOptions | 否 | 当前仅支持配置是否开启抗锯齿功能,默认为关闭。 |
表1 ContextAttrOptions。
参数名 | 类型 | 说明 |
antialias | boolean | 是否开启抗锯齿功能,默认为false。 |
- 返回值
类型 | 说明 |
用于在画布组件上绘制矩形、文本、图片等。 |
fillRect
fillRect(x: number, y: number, width:number, height: number): void。
填充一个矩形。
- 参数
参数 | 类型 | 描述 |
x | number | 指定矩形左上角点的x坐标。 |
y | number | 指定矩形左上角点的y坐标。 |
width | number | 指定矩形的宽度。 |
height | number | 指定矩形的高度。 |
fillText
fillText(text: string, x: number, y: number): void。
绘制填充类文本。
- 参数
参数 | 类型 | 描述 |
text | string | 需要绘制的文本内容。 |
x | number | 需要绘制的文本的左下角x坐标。 |
y | number | 需要绘制的文本的左下角y坐标。 |
代码实现
1、html代码
<div class="container" >
<text class="times">
游戏用时:{{ currentTime}} 秒
</text>
<stack class="stack">
<canvas class="canvas" ref="canvas" onswipe="onSwipeGrids"></canvas>
<div class="success" show="{{isShow}}">
<text class="gameOver">
你真滴棒!
</text>
</div>
</stack>
<input type="button" value="开始游戏" class="tip" onclick="startGame"/>
</div>
2、css代码
.container {
flex-direction: column;
justify-content: center;
align-items: center;
width:100%;
height:100%;
margin: 0 auto;
}
.times{
font-size: 25px;
text-align:center;
width:300px;
letter-spacing:0px;
}
.canvas{
width:100%;
height:100%;
background-color: #FFEFD5 ;
}
.tip{
width:150px;
height:35px;
background-color: #20B2AA;
font-size:25px;
margin-top:10px;
margin-bottom: 5px;
}
.stack{
width: 305px;
height: 305px;
margin-top: 10px;
}
.success {
left:50px;
top:95px;
width: 220px;
height: 130px;
justify-content: center;
align-items: center;
background-color: #E9C2A6;
}
.gameOver {
font-size: 38px;
color: black;
}
3、 js代码
var grids;
var context;
var timer;
const sideLen = 70; // 方格的边长
const margin = 5; // 方格的间距
export default {
data: {
currentTime: '0.0', // 游戏用时
isShow: false, // 控制‘你真滴棒’弹出框的显示或隐藏
},
onInit() {
// 二维数组grids
grids = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 0]];
},
isInitGrids() {
let array = ["left", "up", "right", "down"];
for (let i = 0; i < 100; i++) {
let randomIndex = Math.floor(Math.random() * 4); // 生成随机整数
let direction = array[randomIndex]; // 获取上下左右方向值
this.changeGrids(direction);
}
},
onReady() {
this.isInitGrids();
},
onShow() {
context = this.$refs.canvas.getContext('2d'); // 获取canvas绘图上下文
this.drawGrids();
},
drawGrids() {
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
let gridStr = grids[row][column].toString();
context.fillStyle = "#87CEEB"; // context的方格的颜色
let leftTopX = column * (margin + sideLen) + margin; // X坐标
let leftTopY = row * (margin + sideLen) + margin; // y坐标
context.fillRect(leftTopX, leftTopY, sideLen, sideLen); // 填充
context.textBaseline = 'top'
context.font = "30px";
if (gridStr != "0") { // 除空白格外其他的格子
context.fillStyle = "#000000"; // 数字的颜色
let offsetX = (4 - gridStr.length) * (sideLen / 8);
let offsetY = (sideLen - 30) / 2;
context.fillText(gridStr, leftTopX + offsetX, leftTopY + offsetY); // 绘制填充文本
}
}
}
},
// 点击开始游戏后计时的方法
runIt() {
this.currentTime = (Math.floor(parseFloat(this.currentTime) * 10 + 1) / 10).toString();
if (parseFloat(this.currentTime) % 1 == 0) {
this.currentTime = this.currentTime + ".0";
}
},
// 滑动事件的方法
onSwipeGrids(e) {
this.changeGrids(e.direction);
this.drawGrids();
// 如果this.gameOver()返回true,则清除定时,显示“你真滴棒”表示游戏结束
if (this.gameOver()) {
clearInterval(timer);
this.isShow = true;
}
},
// 判断游戏结束的函数
gameOver() {
// 定义一个成功的二维数组oriGrids
let oriGrids = [[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 0]];
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
// 如果二维数组grids不等于二维数组oriGrids返回false继续游戏
if (grids[row][column] != oriGrids[row][column]) {
return false;
}
}
}
return true; // 结束游戏
},
// 点击挪动网格
changeGrids(direction) {
let x;
let y;
for (let row = 0; row < 4; row++) {
for (let column = 0; column < 4; column++) {
if (grids[row][column] == 0) { // 拿到坐标
x = row;
y = column;
break;
}
}
}
let temp;
if (this.isShow == false) {
if (direction == 'up' && (x + 1) < 4) { // 向上移动(x+1必须小于四)
temp = grids[x + 1][y];
grids[x + 1][y] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'down' && (x - 1) > -1) { // 向下移动(x-1必须大于负一)
temp = grids[x - 1][y];
grids[x - 1][y] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'left' && (y + 1) < 4) { // 向左移动(y + 1必须小于四)
temp = grids[x][y + 1];
grids[x][y + 1] = grids[x][y];
grids[x][y] = temp;
} else if (direction == 'right' && (y - 1) > -1) { // 向右移动(y-1必须大于负一)
temp = grids[x][y - 1];
grids[x][y - 1] = grids[x][y];
grids[x][y] = temp;
}
}
},
startGame() {
timer = setInterval(this.runIt, 100); // 1秒定时执行
this.isInitGrids();
this.currentTime = "0.0"; // 初始化游戏用时
this.isShow = false;
this.onShow();
}
}
总结
H5中使用的样式或者方法有些是在OpenHarmony开发过程中无法使用的,要进行FA开发需要多读OpenHarmony的文档,后续的开发中也需要多踩坑,多总结,多练习!