原生JavaScript实现简易拼图游戏:从Canvas绘制到交互逻辑
本文详解如何使用原生JavaScript开发简易拼图游戏。内容涵盖Canvas图形绘制与刷新机制、触屏与键盘事件处理、定时器应用,以及随机序列生成、方块移动判断与完成检测等核心逻辑,帮助开发者掌握前端游戏开发基础。
前言
本文旨在阐述如何运用原生 JavaScript
构建一款简易的拼图游戏。

游戏开发的基础逻辑
一、游戏开发的基础逻辑
使用编程语言开发游戏前,需掌握其基础逻辑实现,包括图像绘制、交互处理及定时器等核心功能。
1、图形绘制
图形绘制是游戏开发的基础,此处利用 JavaScript 在 canvas 元素上进行渲染。具体步骤为:在 HTML 中创建 canvas 元素,随后在 JavaScript 中通过 id 获取该元素,并获取对应的上下文环境 context,为后续绘图操作奠定基础。
<canvas id="background" width="450px" height="450px"></canvas>
var background = document.getElementById("background");
var context = background.getContext('2d');
利用 context 的 drawImage 方法可绘制图片,此处对相关功能进行了封装:
注意:必须在图片加载完成后调用 drawImage 方法进行绘制,即在 onload 事件中执行,否则会导致绘制失败。
var drawImageItem = function(index, position) {
var img = new Image();
img.src = './image/dog_0' + String(index+1) + '.jpg';
img.onload = () => {
var rect = rectForPosition(position);
context.drawImage(img, rect[0], rect[1], rect[2], rect[3]);
}
}
图片绘制完成后,需动态刷新视图,否则 canvas 仅显示静态图像。对于简单图形刷新,可在原位置重新绘制以覆盖旧图;但有时仅需清除原有图形而不绘制新图案,例如在拼图中将方块移动后,需清空原位置。
利用 context 的 clearRect 方法可实现区域清除。以下是清除 canvas 指定区域的代码示例:
var originRect = rectForPosition(origin);
context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
2、事件处理
完成图形绘制后,需处理玩家输入事件,并据此决定视图刷新时机。输入事件主要分为三类:移动端触屏事件、PC端鼠标事件及键盘事件。
JavaScript 对触屏和鼠标点击的监听机制相同,均通过 canvas 的 onclick 事件进行回调,具体实现如下:
// 屏幕点击
background.onclick = function(e) {
};
可通过 e.offsetX 和 e.offsetY 获取触控点在 canvas 坐标系中的位置。
注意:canvas 的坐标原点位于左上角,即左上角坐标为 (0, 0)。
键盘按键事件则通过 document 的 onkeyup(按键抬起)和 onkeydown(按键按下)等事件进行回调。通过 keyCode 可识别具体按键,进而根据不同按键执行相应逻辑,示例如下:
if (event.keyCode == '37') { // 左
// do something
} else if (event.keyCode == '38') { // 上
// do something
} else if (event.keyCode == '39') { // 右
// do something
} else if (event.keyCode == '40') { // 下
// do something
}
3、定时器
除玩家输入外,有时需定期刷新视图,例如贪吃蛇游戏中需定期更新蛇的位置。
此时需使用定时器定期执行视图刷新代码。通过 setInterval 方法可实现此功能:
setInterval("run()", 100);
上述代码表示每隔 100 毫秒执行一次 run 方法。
拼图游戏的核心逻辑
二、拼图游戏的核心逻辑
掌握基础逻辑后,接下来探讨拼图逻辑的具体实现。
1、生成随机序列
并非任意序列均可通过平移还原,因此不能简单生成随机序列。例如序列 1、0、2、3、4、5、6、7、8 无论怎样平移均无法还原。
本文采用的策略是:预先设定 4 个可还原序列,从中随机选取一个,再对序列进行若干步模拟平移。此举旨在保证初始序列的多样性与可还原性,具体代码如下:
var setupRandomPosition = function() {
var list1 = [4, 3, 2, 8, 0, 7, 5, 6, 1];
var list2 = [2, 0, 5, 6, 8, 7, 3, 1, 4];
var list3 = [3, 7, 2, 4, 1, 6, 8, 0, 5];
var list4 = [3, 2, 4, 1, 7, 6, 5, 0, 8];
var lists = [list1, list2, list3, list4];
imageIndexForPosition = lists[parseInt(Math.random() * 4)];
// 获取空位位置
var emptyPosition = 0;
for (var i = imageIndexForPosition.length - 1; i >= 0; i--) {
if (imageIndexForPosition[i] == lastIndex()) {
emptyPosition = i;
break;
}
}
background.emptyPosition = emptyPosition;
// 随机移动次数
var times = 10;
while (times--) {
// 获取随机数,决定空位哪个位置进行移动
var direction = parseInt(Math.random() * 4);
var target = -1;
if (direction == 0) {
target = topOfPosition(emptyPosition); // 上
} else if (direction == 1) {
target = leftOfPosition(emptyPosition); // 左
} else if (direction == 2) {
target = rightOfPosition(emptyPosition); // 右
} else if (direction == 3) {
target = bottomOfPosition(emptyPosition); // 下
}
if (target < 0 || target > lastIndex()) { // 位置不合法,继续下一次循环
continue;
}
var result = moveImageIfCanAtPosition(target);
if (result >= 0) { // 如果移动成功,更新空位的位置
emptyPosition = target;
}
}
}
2、判断方块是否可移动
序列保存使用 0~8 共 9 个数字,其中空白方块对应数字 8 的位置。判断可移动的唯一条件是目标位置的值是否为 8。代码如下:
var isPositionEmpty = function(position) {
if (position < 0 || position > lastIndex()) {
return false;
}
if (imageIndexForPosition[position] == lastIndex()) {
return true;
} else {
return false;
}
}
上述代码中 lastIndex() 的值为 8。
3、实现方块移动
方块移动逻辑较为简单:先清除旧位置图形,再在新位置绘制新图形。
var refreshImagePositions = function(origin, target) {
var originRect = rectForPosition(origin);
context.clearRect(originRect[0], originRect[1], originRect[2], originRect[3]);
drawImageItem(imageIndexForPosition[target], target);
}
4、检查游戏是否完成
判断图案是否还原,只需遍历数组检查其是否有序即可。
var checkIfFinish = function() {
for (var index = 0; index < imageIndexForPosition.length; index++) {
if (index != imageIndexForPosition[index]) {
return false;
}
}
return true;
}
5、交互事件屏蔽
图案还原后,需屏蔽玩家通过键盘或鼠标移动方块的操作,此时需对交互事件进行屏蔽。
只需设置一个标志位即可实现:
//
屏幕点击
background.onclick = function(e) {
if (isFinish) {
return;
}
// do something
};
// 键盘按钮事件
document.onkeyup = function(event) {
if (isFinish) {
return;
}
// do something
}
图案还原后,标志位 isFinish 被置为 true。在屏幕点击和键盘响应事件的起始处添加判断,若游戏已结束,则不再执行方块移动逻辑。
总结
以上内容为本文全部要点,希望能为读者的学习或工作提供参考。如有疑问欢迎留言交流,感谢支持。
JS监听滚动事件:回到顶部按钮的显示与隐藏逻辑
2026-11-05 16:19:37
JavaScript怎么读写LocalStorage与SessionStorage
2026-11-05 15:40:11
anime.js 与 GSAP 对比:轻量级项目该怎么选择动画库
2026-11-05 11:24:55
flv.js 与 hls.js 在直播场景下的选型对比
2026-11-05 08:18:52
JavaScript能做什么?前端开发中的作用与应用场景解析
2026-11-04 23:17:54
