본문 바로가기

뚱땅뚱땅

[HTML5/JavaScript] 직소퍼즐 만들기 4(完) : 퍼즐 게임으로 만들기

dog-foooot.tistory.com/22

 

[HTML5/Javascript] 직소퍼즐 만들기 3: 퍼즐 조각 무작위로 섞기

dog-foooot.tistory.com/21 [HTML5/JavaScript] 직소퍼즐 만들기 - 2: 드래그드롭으로 퍼즐넣기 dog-foooot.tistory.com/20 [HTML5/JavaScript] 직소퍼즐 만들기 - 1 : 파일 입력 안녕하세요, 김선진입니다. 주말..

dog-foooot.tistory.com

안녕하세요, 김선진입니다.

직소 퍼즐 마지막 시리즈입니다. 직소 퍼즐을 게임으로 만들자!

 

1. 퍼즐 조각이 맞춰졌을 때 성공 여부 검사

2. 퍼즐 맞추기 타이머 생성

3. CSS (알아서 하시길)

 

기존 코드에 이어서 작업합니다.

 

1. 퍼즐 성공 여부 검사

1-1. td에 index부여하기

저번 코드에서 전역으로 선언해놓은 퍼즐 조각 리스트를 이용하여 퍼즐 성공을 검사하는 로직을 짜보자.

간단하게 4*4 퍼즐을 1중 배열이라 생각하고 인덱싱해서 결과물 배열을 만들고, 초기 리스트와 결과물이 같은 경우 성공 판정을 한다.

먼저 td를 생성할 때 해당 index를 id로 설정한다.

 tableData.id = `piece_${x * numColsToCut + y}`;

2*2로 생성했을 때의 예시 인덱스

1-2. 결과 배열과 기존 배열을 비교하여 성공 판정

성공 판정은 간단하게 구현했다. 배열 두 개를 받아 두 배열이 같은지만 검사한다.

const completePuzzle = (puzzle, result) => puzzle.every((piece, index) =>piece === result[index]);

1-3. drop함수 수정

const index = ev.target.id.replace('piece_', '');
  resultPieces[Number(index)] = data;
  if (completePuzzle(originImagePieces, resultPieces)) window.alert('퍼즐 성공!');

기존 코드 아래에 추가해준다.

이걸로 간단하게 퍼즐을 검증해서 성공 시에는 알람을 준다.

인덱스 대신 id를 긁었다 말았다 하는 이유는 elements만 보고 퍼즐을 맞출 수 없게 하기 위함이다.

그리고, 다시 시작하는 함수에 아래 코드도 추가해준다.

while(resultPieces.length > 0) {
    resultPieces.pop();
}

 

2. 퍼즐 맞추기 타이머

2-1. setInterval로 타이머 생성하기

const maxTime = 30;
let nowTime = 0;
let timer;
function startTimer() {
timer = window.setInterval(() => {
	if(nowTime === maxTime) {
		window.clearInterval(timer);
		suffleRendering();
		window.alert('시간 종료!');
	}
	nowTime += 1;
	
}, 1000);
}

 

startTimer라는 함수를 만들어 우리의 maxTime까지 기다려주게 한다.

게임을 시작함과 동시에 timer가 세팅되기 때문에 게임이 종료된 후에는 suffle을 한번 더 돌려줘야 한다.

그리고 처음 퍼즐을 맞추기 시작했을 때 다시 timer를 시작해주면 된다.

  if (resultPieces.length === 0) {
	startTimer();
  }

(아니면 게임 시작, 다시하기 등의 버튼을 제공해줘도 좋다.)

 

3. 전체 js 코드

더보기

전체 변경된 코드는 길어서 접었다.

const numColsToCut = 4;
const numRowsToCut = 4;
const imagePieces = [];
const originImagePieces = [];
const resultPieces = new Array(numColsToCut*numRowsToCut);
function suffleList(array) {
  for (let i = array.length - 1; i > 0; i -= 1) {
    let j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
}
function suffleRendering() {
const box = document.getElementById('puzzle-box');
suffleList(imagePieces);
while(resultPieces.length > 0) {
    resultPieces.pop();
}
imagePieces.forEach(img => {
	box.appendChild(img);
	});
}

const maxTime = 30;
let nowTime = 0;
let timer;
function startTimer() {
timer = window.setInterval(() => {
	if(nowTime === maxTime) {
		window.clearInterval(timer);
		suffleRendering();
		window.alert('시간 종료!');
	}
	nowTime += 1;
	
}, 1000);
}

function allowDrop(ev) {
  ev.preventDefault();
}

function drag(ev) {
  ev.dataTransfer.setData("text", ev.target.id);
}

const completePuzzle = (puzzle, result) => puzzle.every((piece, index) =>piece === result[index]);

function drop(ev) {
  ev.preventDefault();
  var data = ev.dataTransfer.getData("text");
  const child = document.getElementById(data);
  if (!data) return;
  if (resultPieces.length === 0) {
	startTimer();
  }
  if (ev.target.nodeName !== 'TD') {
    console.log(ev.target.parentNode);
    const currentImage = ev.target;
    const td = ev.target.parentNode;
    td.removeChild(currentImage);
    td.appendChild(child)
    const box = document.getElementById('puzzle-box');
    box.appendChild(currentImage);
    return;
  }
  ev.target.appendChild(document.getElementById(data));
  const index = ev.target.id.replace('piece_', '');
  resultPieces[Number(index)] = data;
  if (completePuzzle(originImagePieces, resultPieces)) window.alert('퍼즐 성공!');
}

function updateImageDisplay() {
  const preview = document.querySelector('.preview');
  const input = document.querySelector('input');
  const board = document.getElementById('puzzle-board');

  while(preview.firstChild) {
    preview.removeChild(preview.firstChild);
  }
  const curFiles = input.files;
    for(const file of curFiles) {
         const para = document.createElement('p');
         const imageItem = document.createElement('div');
           const img = new Image();
           img.onload = function() {
             const widthOfOnePiece = this.width/numColsToCut;
             const heightOfOnePiece = this.height/numRowsToCut;
             para.innerHTML = `${numColsToCut}X${numRowsToCut}로 생성된 퍼즐입니다.`;

              while(board.firstChild) {
                board.removeChild(board.firstChild);
              }
                 for(var x = 0; x < numColsToCut; ++x) {
                    let tableRow = document.createElement('tr');
                     for(var y = 0; y < numRowsToCut; ++y) {
                         var canvas = document.createElement('canvas');
                         canvas.width = widthOfOnePiece;
                         canvas.height = heightOfOnePiece;
                         var context = canvas.getContext('2d');
                         context.drawImage(img, y * widthOfOnePiece, x * heightOfOnePiece, widthOfOnePiece, heightOfOnePiece, 0, 0, canvas.width, canvas.height);
                         let pieceImage = new Image();
                         pieceImage.src = canvas.toDataURL();
                         pieceImage.id = canvas.toDataURL();
                         pieceImage.draggable = true;
                         pieceImage.ondragstart = drag;
                         let tableData = document.createElement('td');
                         tableData.ondrop = drop;
                         tableData.ondragover = allowDrop;
                         tableData.width = widthOfOnePiece;
                         tableData.height = heightOfOnePiece;
                         tableData.id = `piece_${x * numColsToCut + y}`;
                         tableRow.appendChild(tableData);
		   originImagePieces.push(pieceImage.src);
                         imagePieces.push(pieceImage);
                     }
                     board.appendChild(tableRow);
                 }
	suffleRendering();
	startTimer();
	}	
           img.src = URL.createObjectURL(file);

           imageItem.appendChild(img);
           imageItem.appendChild(para);
           preview.appendChild(imageItem);
     }
}

 

퍼즐게임 끝.

재미로 만들어본 프로젝트라 코드가 난잡하고 더럽지만,

재미로 하기에는 아주 좋은 프로젝트였다.

그럼 이만~.