How To Create Image Puzzle Game in JavaScript
In this JavaScript Tutorial we will see How to Create a puzzle game using JavaScript With HTML and CSS.
Players can choose an image and select from 5 different difficulty levels (4x4 to 8x8 grids) and compete against time while tracking their moves.
The Game Features:
- Dynamically slice any uploaded image into puzzle pieces.
- Multiple difficulty levels from beginner-friendly 4x4 grids to challenging 8x8 grids with 64 pieces. .
- Move counter and timer.
- Smooth piece-swapping animations.
- Winning detection and celebration.
What We Are Gonna Use In This Project:
- JavaScript Programming Language.- HTML and CSS.
- Visual Studio Editor.
- Visual Studio Editor.
Project Source Code:
- Image Slicer and Randomizer.
/**
* Slices the image into pieces and randomizes their positions
* @param {Image} image - The image to slice into puzzle pieces
*/
function sliceAndRandomizeImage(image) {
// Get the container for puzzle pieces
const sliceContainer = document.getElementById('sliceContainer');
sliceContainer.innerHTML = ''; // Clear previous puzzle pieces
// Create a temporary canvas to work with the image
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const displaySize = 600; // Fixed size for the displayed image
canvas.width = displaySize;
canvas.height = displaySize;
// Draw the image onto the canvas, scaling it to our fixed size
ctx.drawImage(image, 0, 0, displaySize, displaySize);
const slices = []; // Array to hold all puzzle pieces
// Calculate dimensions of each puzzle piece
const sliceWidth = canvas.width / sliceCount;
const sliceHeight = canvas.height / sliceCount;
// Create individual puzzle pieces
for (let row = 0; row < sliceCount; row++) {
for (let col = 0; col < sliceCount; col++) {
// Create a canvas for each puzzle piece
const sliceCanvas = document.createElement('canvas');
const sliceCtx = sliceCanvas.getContext('2d');
sliceCanvas.width = sliceWidth;
sliceCanvas.height = sliceHeight;
// Draw the corresponding portion of the original image
sliceCtx.drawImage(
canvas,
col * sliceWidth, row * sliceHeight, sliceWidth, sliceHeight,//source
0, 0, sliceWidth, sliceHeight // destination rectangle
);
// Create an image from the slice canvas
const sliceImg = document.createElement('img');
sliceImg.src = sliceCanvas.toDataURL();
// Create the div element that will contain the image
const sliceDiv = document.createElement('div');
sliceDiv.className = 'slice';
sliceDiv.appendChild(sliceImg);
// Store original position data
sliceDiv.dataset.row = row;
sliceDiv.dataset.col = col;
// Add click event to the slice
sliceDiv.addEventListener('click', function() {
onSliceClick(sliceDiv);
});
slices.push(sliceDiv);
}
}
// Randomize the order of slices
shuffleArray(slices);
// Add all puzzle pieces to the container
slices.forEach(slice => {
sliceContainer.appendChild(slice);
});
// Update the grid layout based on the current level
sliceContainer.style.gridTemplateColumns = `repeat(${sliceCount}, 1fr)`;
// Reset the move count
moveCount = 0;
document.getElementById('moveCount').textContent = moveCount;
}
-Array Shuffler (Fisher-Yates Algorithm).
/**
* Shuffles array elements randomly (Fisher-Yates algorithm)
* @param {Array} array - The array to shuffle
*/
function shuffleArray(array) {
// Loop through array from end to beginning
for (let i = array.length - 1; i > 0; i--) {
// Pick a random element from 0 to i
const j = Math.floor(Math.random() * (i + 1));
// Swap elements i and j
[array[i], array[j]] = [array[j], array[i]];
}
}
- Slice Click Handler, Manages puzzle piece selection and swapping.
/**
* Handles click events on puzzle pieces
* @param {HTMLElement} slice - The clicked puzzle piece
*/
function onSliceClick(slice) {
// If no piece is currently selected, select this one
if (firstSelectedSlice === null) {
firstSelectedSlice = slice;
slice.classList.add('selected'); // Highlight the selected piece
}
else{
// If a piece is already selected, swap it with the current one
const secondSelectedSlice = slice;
// Don't count clicking the same piece twice as a move
if (firstSelectedSlice === secondSelectedSlice) {
firstSelectedSlice.classList.remove('selected');
firstSelectedSlice = null;
return;
}
// Swap the two selected pieces
swapSlices(firstSelectedSlice, secondSelectedSlice);
firstSelectedSlice.classList.remove('selected');
firstSelectedSlice = null;
// Increment move counter and update display
moveCount++;
document.getElementById('moveCount').textContent = moveCount;
// Check if puzzle is complete after the swap
checkPuzzleComplete();
}
}
- Determines if the puzzle is solved.
/**
* Checks if the puzzle is completed (all pieces in correct position)
*/
function checkPuzzleComplete() {
const slices = document.querySelectorAll('.slice');
let isComplete = true;
// Check each piece's current position against its original position
for (let i = 0; i < slices.length; i++) {
// Calculate where this piece should be in a completed puzzle
const row = Math.floor(i / sliceCount);
const col = i % sliceCount;
// If any piece is out of place, puzzle is not complete
if (slices[i].dataset.row != row || slices[i].dataset.col != col) {
isComplete = false;
break;
}
}
// If puzzle is complete, show completion modal
if (isComplete) {
stopTimer();
//showPuzzleCompleteModal();
// Show modal after 3 seconds
setTimeout(() => {
showPuzzleCompleteModal();
}, 3000); // 1000 milliseconds = 3 seconds
}
}
- Animates the exchange of two puzzle pieces.
/**
* Swaps two puzzle pieces with animation
* @param {HTMLElement} slice1 - First puzzle piece
* @param {HTMLElement} slice2 - Second puzzle piece
*/
function swapSlices(slice1, slice2) {
// Add animation class
slice1.classList.add('swapping');
slice2.classList.add('swapping');
// Get parent and position references
const parent = slice1.parentNode;
const sibling = slice1.nextSibling === slice2 ? slice1 : slice1.nextSibling;
// Swap the DOM elements
slice2.parentNode.insertBefore(slice1, slice2);
parent.insertBefore(slice2, sibling);
// Remove animation class after animation completes
setTimeout(() => {
slice1.classList.remove('swapping');
slice2.classList.remove('swapping');
}, 600);
}
- Start, Stop and Update the Timer.
/**
* Starts the game timer
*/
function startTimer() {
stopTimer(); // Clear any existing timer
seconds = 0;
timer = setInterval(updateTimer, 1000);
}
/**
* Stops the game timer
*/
function stopTimer() {
clearInterval(timer);
}
/**
* Updates the timer display every second
*/
function updateTimer() {
seconds++;
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
// Format time as MM:SS
document.getElementById('timer').textContent =
`${minutes.toString().padStart(2, '0')}:
${remainingSeconds.toString().padStart(2, '0')}`;
}
- Shows the victory screen with statistics.
/**
* Shows the puzzle completion modal with stats
*/
function showPuzzleCompleteModal() {
const modal = document.getElementById('puzzleCompleteModal');
// Display completion stats
document.getElementById('completedLevel').textContent = level;
document.getElementById('completionTime').textContent =
document.getElementById('timer').textContent;
document.getElementById('completionMoves').textContent = moveCount;
modal.style.display = 'block';
}
- Restores the game to its initial state.
/**
* Resets the game state
*/
function resetGame() {
// If an image has been selected, re-slice it
const fileInput = document.getElementById('fileInput');
if (fileInput.files.length > 0) {
const file = fileInput.files[0];
const reader = new FileReader();
reader.onload = function(e) {
const img = new Image();
img.src = e.target.result;
img.onload = function() {
sliceAndRandomizeImage(img);
startTimer();
}
}
reader.readAsDataURL(file);
}
// Update level display
document.getElementById('level').textContent = level;
moveCount = 0;
document.getElementById('moveCount').textContent = moveCount;
}
The Final Result:
if you want the source code click on the download button below
disclaimer: you will get the source code, and to make it work in your machine is your responsibility and to debug any error/exception is your responsibility this project is for the students who want to see an example and read the code not to get and run.
Download Projects Source Code