vue实现拼图
Vue 实现拼图游戏的方法
数据驱动拼图布局
使用Vue的响应式数据管理拼图状态。创建一个二维数组表示拼图格子,每个格子包含当前显示的图片片段索引或空白格标识。通过v-for指令动态渲染拼图DOM元素。
data() {
return {
puzzle: [
[1, 2, 3],
[4, 5, 6],
[7, 8, null] // null表示空白格
],
imageParts: [] // 存储分割后的图片片段
}
}
图片分割处理
使用canvas将原图分割为等份的小图。通过计算每个片段的坐标位置,使用drawImage方法截取对应区域并转换为图片URL存储。
methods: {
splitImage() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const partSize = this.image.width / this.gridSize;
for (let y = 0; y < this.gridSize; y++) {
for (let x = 0; x < this.gridSize; x++) {
canvas.width = partSize;
canvas.height = partSize;
ctx.drawImage(
this.image,
x * partSize, y * partSize, partSize, partSize,
0, 0, partSize, partSize
);
this.imageParts.push(canvas.toDataURL());
}
}
}
}
拖拽交互实现
为拼图块添加draggable属性,通过@dragstart和@drop事件处理移动逻辑。验证目标位置是否为空白格相邻位置,更新puzzle数组触发视图重新渲染。
<div
v-for="(row, y) in puzzle"
:key="y"
class="puzzle-row"
>
<div
v-for="(cell, x) in row"
:key="x"
class="puzzle-cell"
:draggable="cell !== null"
@dragstart="handleDragStart($event, y, x)"
@dragover.prevent
@drop="handleDrop($event, y, x)"
>
<img
v-if="cell !== null"
:src="imageParts[cell - 1]"
/>
</div>
</div>
移动验证逻辑
检查拖动源与目标位置是否相邻(曼哈顿距离为1),且目标位置为空白格。满足条件时交换两个位置的数值。
methods: {
handleDrop(event, targetY, targetX) {
if (this.puzzle[targetY][targetX] !== null) return;
const sourceY = parseInt(event.dataTransfer.getData('y'));
const sourceX = parseInt(event.dataTransfer.getData('x'));
if (Math.abs(sourceY - targetY) + Math.abs(sourceX - targetX) === 1) {
this.$set(this.puzzle[targetY], targetX, this.puzzle[sourceY][sourceX]);
this.$set(this.puzzle[sourceY], sourceX, null);
this.checkCompletion();
}
}
}
完成状态检测
每次移动后遍历拼图数组,验证所有元素是否按顺序排列。当拼图完成时显示成功提示。
methods: {
checkCompletion() {
let expected = 1;
for (let y = 0; y < this.gridSize; y++) {
for (let x = 0; x < this.gridSize; x++) {
if (y === this.gridSize - 1 && x === this.gridSize - 1) {
if (this.puzzle[y][x] !== null) return false;
} else if (this.puzzle[y][x] !== expected++) {
return false;
}
}
}
alert('拼图完成!');
return true;
}
}
响应式样式设计
使用CSS Grid布局拼图容器,确保拼图块间距均匀。为拼图块添加过渡效果提升交互体验。
.puzzle-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2px;
width: 300px;
}
.puzzle-cell {
aspect-ratio: 1;
border: 1px solid #ddd;
transition: transform 0.2s;
}
.puzzle-cell img {
width: 100%;
height: 100%;
object-fit: cover;
}
初始化洗牌算法
游戏开始时使用Fisher-Yates算法随机打乱拼图,确保有解状态。通过模拟合法移动实现随机打乱。
methods: {
shufflePuzzle() {
// 模拟100次随机合法移动
let blankY = this.gridSize - 1;
let blankX = this.gridSize - 1;
for (let i = 0; i < 100; i++) {
const directions = [
{y: blankY - 1, x: blankX},
{y: blankY + 1, x: blankX},
{y: blankY, x: blankX - 1},
{y: blankY, x: blankX + 1}
].filter(pos =>
pos.y >= 0 && pos.y < this.gridSize &&
pos.x >= 0 && pos.x < this.gridSize
);
const randomDir = directions[Math.floor(Math.random() * directions.length)];
[this.puzzle[blankY][blankX], this.puzzle[randomDir.y][randomDir.x]] =
[this.puzzle[randomDir.y][randomDir.x], this.puzzle[blankY][blankX]];
blankY = randomDir.y;
blankX = randomDir.x;
}
}
}






