1.案例需求
用JavaScript做一个4*4的拼图游戏,实现其基本功能及其他拓展功能,如:游戏计时功能的实现、原图参照物、添加音乐播放器、添加移动拼图的次数记录器等。
2.编程思路
1、实现整体布局设计
2、实现游戏布局设计
3、实现游戏逻辑
3.案例源码
HTML源码
<body>
<div id="container">
<!-- 页面标题 -->
<h3>拼图游戏</h3>
<!-- 水平线 -->
<hr />
<!-- 游戏时间、步数、音乐按钮 -->
<div id="timeBox">共计时间:<span id="time">00:00:00</span></div>
<div style="display: flex; justify-content: center; align-items: center">
背景音乐:
<img id="bofang" width="30px" src="image/play.png" alt="" />
</div>
<audio
id="bgmusic"
src="music/如果这就是爱情(1个球版) - 1个球.flac"
></audio>
<div id="countAll">共计步数:<span id="count">0</span></div>
<!-- 游戏画布 -->
<canvas id="myCanvas" width="400" height="400" style="border: 1px solid">
对不起,您的浏览器不支持HTML5画布API</canvas
>
<img width="200px" src="image/puzzle.jpg" alt="" />
<!-- 重新开始 -->
<div id="cxks">
<button onclick="restartGame()">重新开始</button>
</div>
</div>
CSS源码
body {
background-color: silver;/*设置页面背景颜色为银色*/
}
/*设置游戏界面样式*/
#container {
background-color: white;
width: 800px;
margin: auto;
padding: 20px;
text-align: center;
box-shadow: 10px 10px 15px black;
}
/*设置游戏时间面板样式*/
#timeBox {
margin: 10px 0;
font-size: 18px;
}
/*设置游戏按钮样式*/
button {
width: 200px;
height: 50px;
margin: 10px 0;
border: 0;
outline: none;
font-size: 25px;
font-weight: bold;
color: white;
background-color: lightcoral;
}
/*设置鼠标悬浮时的按钮样式*/
button:hover {
background-color: coral;
}
JavaScript源码
<script>
// 获取画布对象
let c = document.getElementById("myCanvas");
let ctx = c.getContext("2d");
// 获取背景音乐对象
var bgmusic = document.getElementById("bgmusic");
// 获取暂停键对象
var bofang = document.getElementById("bofang");
var flag = 1;
bofang.onclick = function () {
if (flag) {
bofang.src = "image/pause.png";
bgmusic.play();
flag = 0;
} else {
bofang.src = "image/play.png";
bgmusic.pause();
flag = 1;
}
};
// 定义拼图小方块的边长
let w = 100;
// 定义初始化方块位置
let num = [
[00, 01, 02, 03],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33],
];
// 声明拼图素材来源
let img = new Image();
img.src = "image/puzzle.jpg";
// 当图片加载完毕时
img.onload = function () {
// 打乱拼图位置
generateNum();
// 在画布上绘制拼图
drawCanvas();
};
function generateNum() {
// 循坏50次进行拼图的打乱
for (let i = 0; i < 50; i++) {
// 随机抽取其中一个数据
let i1 = Math.round(Math.random() * 3);
let j1 = Math.round(Math.random() * 3);
// 再随机抽取其中一个数据
let i2 = Math.round(Math.random() * 3);
let j2 = Math.round(Math.random() * 3);
//对调他们的位置
let temp = num[i1][j1];
num[i1][j1] = num[i2][j2];
num[i2][j2] = temp;
}
}
// 绘制拼图
function drawCanvas() {
// 清空画布
ctx.clearRect(0, 0, 400, 400);
// 使用双重for循坏绘制4*4的拼图
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
if (num[i][j] != 33) {
// 获取数值的十位数,即第几行
let row = parseInt(num[i][j] / 10);
// 获取数值的个位数,即第几列
let col = num[i][j] % 10;
// 在画布的相关位置上绘图
ctx.drawImage(img, col * w, row * w, w, w, j * w, i * w, w, w);
}
}
}
}
// 监听鼠标单击事件
c.onmousedown = function (e) {
// 获取画布边界
let bound = c.getBoundingClientRect();
// 获取鼠标在画布上的坐标位置(x,y)
let x = e.pageX - bound.left;
let y = e.pageY - bound.top;
// 将x和y换算成几行几列
let row = parseInt(y / 100);
let col = parseInt(x / 100);
// 如果当前单击的不是空白区域
if (num[row][col] != 33) {
// 移动单击的方块
detectBox(row, col);
// 重新绘制画布
drawCanvas();
// 检查游戏是否成功
let isWin = checkWin();
// 如果游戏成功
if (isWin) {
// 清除计时器
clearInterval(timer);
// 绘制完整图片
ctx.drawImage(img, 0, 0);
// 设置字体为serif,加粗,68号字
ctx.font = "bold 68px serif";
ctx.fillStyle = "red";
// 显示提示语句
ctx.fillText("游戏成功!", 20, 150);
}
}
};
// 定义步数为0
let stepCount = 0;
//移动单击的方块
function detectBox(i, j) {
// 如果单击的方块不在最上面一行
if (i > 0) {
//检测空白区域是否在当前方块的正上方
if (num[i - 1][j] == 33) {
// 交换空白区域与当前方块的位置
num[i - 1][j] = num[i][j];
num[i][j] = 33;
// 交换一次步数加1
stepCount++;
// 更新步数
document.getElementById("count").innerText = stepCount;
return;
}
}
// 如果单击的方块不在最下面一行
if (i < 3) {
//检测空白区域是否在当前方块的正下方
if (num[i + 1][j] == 33) {
// 交换空白区域与当前方块的位置
num[i + 1][j] = num[i][j];
num[i][j] = 33;
// 交换一次步数加1
stepCount++;
// 更新步数
document.getElementById("count").innerText = stepCount;
return;
}
}
//如果单击的方块不在最左边一列
if (j > 0) {
//检测空白区域是否在当前方块的左边
if (num[i][j - 1] == 33) {
//交换空白区域与当前方块的位置
num[i][j - 1] = num[i][j];
num[i][j] = 33;
// 交换一次步数加1
stepCount++;
// 更新步数
document.getElementById("count").innerText = stepCount;
return;
}
}
//如果单击的方块不在最右边一列
if (j < 3) {
//检测空白区域是否在当前方块的右边
if (num[i][j + 1] == 33) {
//交换空白区域与当前方块的位置
num[i][j + 1] = num[i][j];
num[i][j] = 33;
// 交换一次步数加1
stepCount++;
// 更新步数
document.getElementById("count").innerText = stepCount;
return;
}
}
}
// 胜利的判断
function checkWin() {
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
// 如果有其中一块方块的位置不对
if (num[i][j] != i * 10 + j) {
// 返回假
return false;
}
}
}
return true;
}
// 获取游戏计时文本区域对象
let time = document.getElementById("time");
//初始化时分秒
let h = 0,
m = 0,
s = 0;
function getCurrentTime() {
// 将时分秒换为整数以便进行自增或赋值
s = parseInt(s);
m = parseInt(m);
h = parseInt(h);
// 每秒变量s先自增1
s++;
if (s == 60) {
s = 0;
m++;
}
if (m == 60) {
m = 0;
h++;
}
// 修改时分秒的显示效果,使其保持两位数
if (s < 10) s = "0" + s;
if (m < 10) m = "0" + m;
if (h < 10) h = "0" + h;
// 将当前计时的时间显示在页面上
time.innerHTML = h + ":" + m + ":" + s;
}
// 重新开始游戏
function restartGame() {
// 清除计时器
clearInterval(timer);
// 时间清零
s = 0;
m = 0;
h = 0;
// 重新显示时间
getCurrentTime();
timer = setInterval("getCurrentTime()", 1000);
// 重新打乱拼图顺序
generateNum();
// 绘制拼图
drawCanvas();
//点击重新开始,计步器初始化为0
stepCount = 0;
// 重新显示计步器
document.getElementById("count").innerHTML = stepCount;
}
// 每隔1000毫秒(1s)刷新一次时间
let timer = setInterval("getCurrentTime()", 1000);
</script>
3.游戏效果及展示
游戏成功效果图
4.小结
制作该拼图小游戏主要运用JavaScript中的DOM操作、事件处理、数组操作等知识,大家可以参考一下,如有问题欢迎大家在评论区提出。其次小伙伴们也可以根据自己的需求更改代码实现自己想要的功能。