一、需要实现的功能
一张完整的图片切割成多个九宫格小块,在打乱排列顺序后,通过拖动小块的位置,重新排列它们以恢复原始图片即成功。这个游戏测试你的观察能力、空间认知能力和逻辑思维能力。它不仅有助于放松大脑,还提供了娱乐和挑战。
二、需求功能细化
1、图片切割
游戏开始时,一张图片会被切割成多个小块,并以随机顺序排列在游戏区域内。
2、打乱拼图
点击"打乱拼图"按钮,可以重新随机排列拼图块的位置。
3、拖拽移动
通过鼠标点击小块并拖拽,可以移动小块的位置。
4、完成拼图
玩家的目标是将拼图块按照正确的顺序重新排列,恢复原始图片。
游戏规则:
游戏开始时,一张图片被切割成多个小块并随机排列在游戏区域内。
使用鼠标点击一个小块,然后拖拽它的位置,将其移动到空白位置或与其他小块交换位置。
继续移动其他小块,逐渐调整它们的位置,以恢复原始图片的完整性。
如果感到困惑或遇到难题,可以点击"打乱拼图"按钮重新排列小块,重新开始。
当所有小块都恰当地拼合在一起,恢复成原始图片时,游戏胜利。
在完成拼图后,会弹出恭喜信息的提示框,可以选择重新开始游戏或继续挑战。
三、H5页面设计
我们创建一个命名为puzzle.html的文件通过编辑器(我用的EditPlus)打开。使用<!DOCTYPE>声明HTML文档类型,确保浏览器以正确的方式渲染网页内容。同时,设置UTF-8编码,以确保浏览器能够正确地解析和显示中文字符。
以下是拼图游戏的基本DOM结构。玩家将在游戏板上看到拼图块,并通过点击按钮来打乱拼图块的位置。你可以根据这个基本结构来进一步实现拼图游戏的逻辑和功能。
<body>
<h1>图片切片拼图游戏</h1>
<div id="puzzle-container">
<div id="puzzle-board"></div>
</div>
<button id="shuffle-btn">打乱拼图</button>
</body>
<h1>图片切换拼图游戏</h1>:标题,使用h1标签,用于显示游戏的名称或标题,让玩家知道这是一个拼图游戏。
<div id="puzzle-container">:这是一个容器,用于包含拼图游戏的主要内容。拼图块将显示在这个容器内。
<div id="puzzle-board"></div>:用于显示拼图块的游戏板。在游戏开始时,拼图块会被放置在这个游戏板上。
<button id="shuffle-btn">打乱拼图</button>:这是一个按钮,当点击它时,会触发打乱拼图的功能。点击这个按钮后,拼图块的位置将被重新随机排列,增加游戏的挑战性。
四、CSS样式设置
上面html已经准备好了,下面我们简单的来配置一下样式吧。
<style>
#puzzle-container {
width: 300px;
height: 300px;
margin: 0 auto;
border: 2px solid #ccc;
position: relative;
overflow: hidden;
}
#puzzle-board {
width: 300px;
height: 300px;
position: absolute;
}
.puzzle-piece {
width: 100px;
height: 100px;
position: absolute;
background-size: 300px 300px;
border: 2px solid #fff;
transition: all 0.3s ease-in-out;
}
button {
display: block;
margin: 20px auto;
}
</style>
#puzzle-container:这是拼图游戏容器的样式。它设置了容器的宽度和高度为300px,并使用margin: 0 auto使其水平居中对齐。还设置了边框样式和相对定位,并使用overflow: hidden属性隐藏超出容器大小的内容。
#puzzle-board:这是拼图游戏板的样式。它设置了游戏板的宽度和高度为300px,并使用position: absolute将其相对于父容器进行定位。
.puzzle-piece:这是拼图块的样式。它设置了拼图块的宽度和高度为100px,并使用position: absolute将其相对于父容器进行定位。background-size: 300px 300px用于调整拼图块背景图的大小以适应游戏板。还设置了边框样式和过渡效果,使拼图块在移动时具有平滑的过渡效果。
button:这是按钮的样式。display: block使按钮以块级元素显示,margin: 20px auto用于将按钮居中对齐。
以上是拼图游戏的基本CSS样式。通过这些样式,游戏容器、游戏板和拼图块将按照指定的样式进行布局和显示。你可以根据这个CSS代码继续完善拼图游戏的样式和外观。
五、代码逻辑,游戏实现
上面我们搭建了好了页面,下面呢我们就通过js代码,实现我们游戏的功能吧。
<script>
document.addEventListener('DOMContentLoaded', () => {
const puzzleContainer = document.getElementById('puzzle-container');
const puzzleBoard = document.getElementById('puzzle-board');
const shuffleButton = document.getElementById('shuffle-btn');
const imageSrc = 'https://www.webppp.com/upload/icecream_animation_cover.png'; // 替换为你的图片地址
const rows = 3;
const cols = 3;
const pieces = [];
let emptyPiece;
let isShuffling = false;
// 创建拼图块
function createPuzzlePieces() {
const pieceWidth = puzzleContainer.offsetWidth / cols;
const pieceHeight = puzzleContainer.offsetHeight / rows;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const piece = document.createElement('div');
piece.className = 'puzzle-piece';
piece.style.width = `${pieceWidth}px`;
piece.style.height = `${pieceHeight}px`;
piece.style.backgroundImage = `url(${imageSrc})`;
piece.style.backgroundPosition = `${-col * pieceWidth}px ${-row * pieceHeight}px`;
piece.style.top = `${row * pieceHeight}px`;
piece.style.left = `${col * pieceWidth}px`;
piece.dataset.row = row;
piece.dataset.col = col;
if (row === rows - 1 && col === cols - 1) {
emptyPiece = piece;
piece.classList.add('empty');
} else {
piece.addEventListener('click', () => {
if (!isShuffling) {
movePiece(piece);
}
});
}
puzzleBoard.appendChild(piece);
pieces.push(piece);
}
}
}
// 移动拼图块
function movePiece(piece) {
const emptyPieceRow = parseInt(emptyPiece.dataset.row);
const emptyPieceCol = parseInt(emptyPiece.dataset.col);
const pieceRow = parseInt(piece.dataset.row);
const pieceCol = parseInt(piece.dataset.col);
if (
(pieceRow === emptyPieceRow && Math.abs(pieceCol - emptyPieceCol) === 1) ||
(pieceCol === emptyPieceCol && Math.abs(pieceRow - emptyPieceRow) === 1)
) {
const tempRow = emptyPieceRow;
const tempCol = emptyPieceCol;
emptyPiece.style.top = `${pieceRow * piece.offsetHeight}px`;
emptyPiece.style.left = `${pieceCol * piece.offsetWidth}px`;
emptyPiece.dataset.row = pieceRow;
emptyPiece.dataset.col = pieceCol;
piece.style.top = `${tempRow * piece.offsetHeight}px`;
piece.style.left = `${tempCol * piece.offsetWidth}px`;
piece.dataset.row = tempRow;
piece.dataset.col = tempCol;
}
checkWin();
}
let isWin = false; // 添加标志位
// 检查是否完成拼图
function checkWin() {
let isPuzzleComplete = true;
for (let i = 0; i < pieces.length; i++) {
const piece = pieces[i];
const row = parseInt(piece.dataset.row);
const col = parseInt(piece.dataset.col);
if (row !== Math.floor(i / cols) || col !== i % cols) {
isPuzzleComplete = false;
break;
}
}
if (isPuzzleComplete && !isWin && !isShuffling) { // 添加条件判断
isWin = true; // 设置标志位为true
setTimeout(() => {
alert('恭喜!你完成了拼图!');
shuffleButton.disabled = false;
isWin = false; // 重置标志位为false
}, 200);
}
}
// 打乱拼图
function shufflePuzzle() {
isShuffling = true;
shuffleButton.disabled = true;
isWin = false; // 重置标志位为false
const shuffleCount = 100;
let count = 0;
const intervalId = setInterval(() => {
const randomIndex = Math.floor(Math.random() * pieces.length);
const randomPiece = pieces[randomIndex];
movePiece(randomPiece);
count++;
if (count >= shuffleCount) {
clearInterval(intervalId);
isShuffling = false;
shuffleButton.disabled = false;
}
}, 10);
}
createPuzzlePieces();
shuffleButton.addEventListener('click', shufflePuzzle);
});
</script>
现在解释一下关键部分的代码。
(1)document.addEventListener('DOMContentLoaded', () => { ... });
表示在文档加载完成后执行的函数,确保在操作DOM之前元素已经存在。
(2)const puzzleContainer = document.getElementById('puzzle-container');
获取 id 为"puzzle-container"的元素,并将其存储在 puzzleContainer 变量中。这个容器元素是整个拼图游戏的外层容器。
(3)const puzzleBoard = document.getElementById('puzzle-board');
获取id为"puzzle-board"的元素,并将其存储在 puzzleBoard 变量中。这个元素是用来放置拼图块的容器。
(4)const shuffleButton = document.getElementById('shuffle-btn');
获取id为"shuffle-btn"的元素,并将其存储在 shuffleButton 变量中。这是一个按钮元素,用于触发打乱拼图的操作。
(5)const imageSrc = '';
一个存储图片地址的变量,用于设置拼图块的背景图片。
(6)const rows = 3; 和 const cols = 3;
定义拼图的行数和列数。
(7)const pieces = [];
创建了一个空数组,用于存储拼图块的DOM元素。
(8)let emptyPiece;
一个用于存储空拼图块的变量。
(9)let isShuffling = false;
一个标志位变量,用于判断是否正在打乱拼图。
(10)function createPuzzlePieces() { ... }
一个创建拼图块的函数。它根据行数和列数循环创建拼图块的DOM元素,并设置它们的样式、背景图片和位置。同时,为非空拼图块添加了点击事件监听器。
(11)function movePiece(piece) { ... }
一个移动拼图块的函数。它根据点击的拼图块和空拼图块的位置关系,交换它们的位置,并更新它们的样式和数据集。
(12)function checkWin() { ... }
一个检查是否完成拼图的函数。它遍历所有拼图块,根据其当前位置与正确位置进行比较,判断是否完成拼图。如果拼图完成,则显示恭喜的提示,并重新启用打乱按钮。
(13)function shufflePuzzle() { ... }
一个打乱拼图的函数。它使用随机算法将拼图块进行打乱,将空拼图和其他拼图块进行交换,并计数打乱次数。在每次交换拼图块后,检查是否完成拼图,如果拼图已经完成,则显示完成提示,并重新启用打乱按钮。
(14)createPuzzlePieces();
调用 createPuzzlePieces() 函数,开始创建拼图块。
(15)shuffleButton.addEventListener('click', shufflePuzzle);
为打乱按钮添加了点击事件监听器,点击按钮将触发 shufflePuzzle() 函数,开始打乱拼图。
这些代码一起实现了一个基于DOM操作的拼图游戏。通过点击拼图块和打乱按钮,可以移动拼图块并打乱拼图,当拼图完成时会显示完成提示。
六、完整源代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片切片拼图游戏</title>
<style>
#puzzle-container {
width: 300px;
height: 300px;
margin: 0 auto;
border: 2px solid #ccc;
position: relative;
overflow: hidden;
}
#puzzle-board {
width: 300px;
height: 300px;
position: absolute;
}
.puzzle-piece {
width: 100px;
height: 100px;
position: absolute;
background-size: 300px 300px;
border: 2px solid #fff;
transition: all 0.3s ease-in-out;
}
button {
display: block;
margin: 20px auto;
}
</style>
</head>
<body>
<h1>图片切片拼图游戏</h1>
<div id="puzzle-container">
<div id="puzzle-board"></div>
</div>
<button id="shuffle-btn">打乱拼图</button>
</body>
<script>
document.addEventListener('DOMContentLoaded', () => {
const puzzleContainer = document.getElementById('puzzle-container');
const puzzleBoard = document.getElementById('puzzle-board');
const shuffleButton = document.getElementById('shuffle-btn');
const imageSrc = 'https://www.webppp.com/upload/icecream_animation_cover.png';
const rows = 3;
const cols = 3;
const pieces = [];
let emptyPiece;
let isShuffling = false;
// 创建拼图块
function createPuzzlePieces() {
const pieceWidth = puzzleContainer.offsetWidth / cols;
const pieceHeight = puzzleContainer.offsetHeight / rows;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const piece = document.createElement('div');
piece.className = 'puzzle-piece';
piece.style.width = `${pieceWidth}px`;
piece.style.height = `${pieceHeight}px`;
piece.style.backgroundImage = `url(${imageSrc})`;
piece.style.backgroundPosition = `${-col * pieceWidth}px ${-row * pieceHeight}px`;
piece.style.top = `${row * pieceHeight}px`;
piece.style.left = `${col * pieceWidth}px`;
piece.dataset.row = row;
piece.dataset.col = col;
if (row === rows - 1 && col === cols - 1) {
emptyPiece = piece;
piece.classList.add('empty');
} else {
piece.addEventListener('click', () => {
if (!isShuffling) {
movePiece(piece);
}
});
}
puzzleBoard.appendChild(piece);
pieces.push(piece);
}
}
}
// 移动拼图块
function movePiece(piece) {
const emptyPieceRow = parseInt(emptyPiece.dataset.row);
const emptyPieceCol = parseInt(emptyPiece.dataset.col);
const pieceRow = parseInt(piece.dataset.row);
const pieceCol = parseInt(piece.dataset.col);
if (
(pieceRow === emptyPieceRow && Math.abs(pieceCol - emptyPieceCol) === 1) ||
(pieceCol === emptyPieceCol && Math.abs(pieceRow - emptyPieceRow) === 1)
) {
const tempRow = emptyPieceRow;
const tempCol = emptyPieceCol;
emptyPiece.style.top = `${pieceRow * piece.offsetHeight}px`;
emptyPiece.style.left = `${pieceCol * piece.offsetWidth}px`;
emptyPiece.dataset.row = pieceRow;
emptyPiece.dataset.col = pieceCol;
piece.style.top = `${tempRow * piece.offsetHeight}px`;
piece.style.left = `${tempCol * piece.offsetWidth}px`;
piece.dataset.row = tempRow;
piece.dataset.col = tempCol;
}
checkWin();
}
let isWin = false; // 添加标志位
// 检查是否完成拼图
function checkWin() {
let isPuzzleComplete = true;
for (let i = 0; i < pieces.length; i++) {
const piece = pieces[i];
const row = parseInt(piece.dataset.row);
const col = parseInt(piece.dataset.col);
if (row !== Math.floor(i / cols) || col !== i % cols) {
isPuzzleComplete = false;
break;
}
}
if (isPuzzleComplete && !isWin && !isShuffling) { // 添加条件判断
isWin = true; // 设置标志位为true
setTimeout(() => {
alert('恭喜!你完成了拼图!');
shuffleButton.disabled = false;
isWin = false; // 重置标志位为false
}, 200);
}
}
// 打乱拼图
function shufflePuzzle() {
isShuffling = true;
shuffleButton.disabled = true;
isWin = false; // 重置标志位为false
const shuffleCount = 100;
let count = 0;
const intervalId = setInterval(() => {
const randomIndex = Math.floor(Math.random() * pieces.length);
const randomPiece = pieces[randomIndex];
movePiece(randomPiece);
count++;
if (count >= shuffleCount) {
clearInterval(intervalId);
isShuffling = false;
shuffleButton.disabled = false;
}
}, 10);
}
createPuzzlePieces();
shuffleButton.addEventListener('click', shufflePuzzle);
});
</script>
</html>
以上是图片切片拼图游戏的完整代码,可以直接复制过去,或者点击游戏demo连接访问。