Веблет для вашего досуга. Простой сайт для игры в Пазл

Веблет для вашего досуга. Простой сайт для игры в Пазл

Простой код html. Кидаете в любой текстовый редактор, сохраняете в формате html. Запускаете, выбираете любую картинку и играете. Работает со смартфона

<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Пазл</title> <style> body { margin: 0; padding: 20px; display: flex; flex-direction: column; align-items: center; background: linear-gradient(135deg, #e0eafc, #cfdef3); font-family: 'Segoe UI', Arial, sans-serif; min-height: 100vh; } #controls { background: rgba(255, 255, 255, 0.9); padding: 15px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; gap: 10px; max-width: 320px; width: 100%; margin-bottom: 20px; } #imageInput, #difficulty, button { padding: 10px; border: none; border-radius: 8px; font-size: 14px; cursor: pointer; transition: all 0.3s ease; } #imageInput { background: #f5f5f5; } #imageInput:hover { background: #e0e0e0; } #difficulty { background: #fff; appearance: none; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); } button { background: #6b7280; color: white; } button:hover { background: #4b5563; } #imagePreview { max-width: 100%; height: auto; border-radius: 8px; margin-top: 10px; display: none; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); } #gameContainer { position: relative; border-radius: 12px; overflow: hidden; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); } .puzzle-piece { position: absolute; border: 1px solid rgba(255, 255, 255, 0.2); box-sizing: border-box; cursor: move; user-select: none; touch-action: none; transition: transform 0.2s ease; } .puzzle-piece:hover { transform: scale(1.02); } .puzzle-piece.movable { z-index: 10; } .puzzle-piece.fixed { z-index: 1; } #winMessage { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(255, 255, 255, 0.95); padding: 20px 40px; border-radius: 12px; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2); text-align: center; font-size: 20px; color: #333; z-index: 100; /* Устанавливаем высокий z-index */ } #winMessage button { margin-top: 15px; background: #10b981; } #winMessage button:hover { background: #059669; } </style> </head> <body> <div id="controls"> <input type="file" id="imageInput" accept="image/*"> <select id="difficulty"> <option value="3">Легко (3x3)</option> <option value="4">Средне (4x4)</option> <option value="5">Сложно (5x5)</option> </select> <button onclick="startGame()">Начать</button> <img id="imagePreview"> </div> <div id="gameContainer"></div> <div id="winMessage"> <p>Пазл собран! Поздравляем!</p> <button onclick="resetGame()">Сыграть снова</button> </div> <script> let img = new Image(); let pieces = []; let gridSize; let pieceWidth, pieceHeight; let container = document.getElementById('gameContainer'); let winMessage = document.getElementById('winMessage'); document.getElementById('imageInput').addEventListener('change', function(e) { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = function(event) { img.src = event.target.result; img.onload = function() { document.getElementById('imagePreview').src = img.src; document.getElementById('imagePreview').style.display = 'block'; } } reader.readAsDataURL(file); } }); function startGame() { if (!img.src) { alert('Загрузите изображение!'); return; } gridSize = parseInt(document.getElementById('difficulty').value); container.innerHTML = ''; winMessage.style.display = 'none'; const maxWidth = Math.min(window.innerWidth * 0.9, img.width); const maxHeight = Math.min(window.innerHeight * 0.7, img.height); const aspectRatio = img.width / img.height; let width = maxWidth; let height = width / aspectRatio; if (height > maxHeight) { height = maxHeight; width = height * aspectRatio; } container.style.width = width + 'px'; container.style.height = height + 'px'; pieceWidth = width / gridSize; pieceHeight = height / gridSize; createPuzzlePieces(); shufflePieces(); } function createPuzzlePieces() { pieces = []; for (let y = 0; y < gridSize; y++) { for (let x = 0; x < gridSize; x++) { const piece = document.createElement('div'); piece.className = 'puzzle-piece movable'; piece.style.width = pieceWidth + 'px'; piece.style.height = pieceHeight + 'px'; piece.style.backgroundImage = `url(${img.src})`; piece.style.backgroundSize = `${container.offsetWidth}px ${container.offsetHeight}px`; piece.style.backgroundPosition = `${-x * pieceWidth}px ${-y * pieceHeight}px`; piece.dataset.correctX = x; piece.dataset.correctY = y; makeDraggable(piece); container.appendChild(piece); pieces.push(piece); } } } function shufflePieces() { pieces.forEach(piece => { const randomX = Math.random() * (container.offsetWidth - pieceWidth); const randomY = Math.random() * (container.offsetHeight - pieceHeight); piece.style.left = randomX + 'px'; piece.style.top = randomY + 'px'; }); } function makeDraggable(element) { let posX = 0, posY = 0, startX = 0, startY = 0; element.onmousedown = dragMouseDown; element.ontouchstart = dragTouchStart; function dragMouseDown(e) { e.preventDefault(); startX = e.clientX; startY = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function dragTouchStart(e) { e.preventDefault(); startX = e.touches[0].clientX; startY = e.touches[0].clientY; document.ontouchend = closeDragElement; document.ontouchmove = elementDragTouch; } function elementDrag(e) { e.preventDefault(); posX = startX - e.clientX; posY = startY - e.clientY; startX = e.clientX; startY = e.clientY; moveElement(); } function elementDragTouch(e) { posX = startX - e.touches[0].clientX; posY = startY - e.touches[0].clientY; startX = e.touches[0].clientX; startY = e.touches[0].clientY; moveElement(); } function moveElement() { element.style.top = Math.max(0, Math.min(element.offsetTop - posY, container.offsetHeight - pieceHeight)) + 'px'; element.style.left = Math.max(0, Math.min(element.offsetLeft - posX, container.offsetWidth - pieceWidth)) + 'px'; } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; document.ontouchend = null; document.ontouchmove = null; checkSnap(element); checkWin(); } } function checkSnap(piece) { const correctX = piece.dataset.correctX * pieceWidth; const correctY = piece.dataset.correctY * pieceHeight; const currentX = parseFloat(piece.style.left); const currentY = parseFloat(piece.style.top); if (Math.abs(currentX - correctX) < 20 && Math.abs(currentY - correctY) < 20) { piece.style.left = correctX + 'px'; piece.style.top = correctY + 'px'; piece.style.cursor = 'default'; piece.onmousedown = null; piece.ontouchstart = null; piece.classList.remove('movable'); piece.classList.add('fixed'); } } function checkWin() { const allPiecesCorrect = pieces.every(piece => Math.abs(parseFloat(piece.style.left) - (piece.dataset.correctX * pieceWidth)) < 1 && Math.abs(parseFloat(piece.style.top) - (piece.dataset.correctY * pieceHeight)) < 1 ); if (allPiecesCorrect) { winMessage.style.display = 'block'; } } function resetGame() { winMessage.style.display = 'none'; startGame(); } window.onresize = () => { if (pieces.length > 0) startGame(); }; </script> </body> </html>
4
2
1
1
6 комментариев