노트

[클라우딩 어플리케이션 엔지니어링 TIL] - 7주차 퍼즐게임 추가 요구사항 본문

TIL

[클라우딩 어플리케이션 엔지니어링 TIL] - 7주차 퍼즐게임 추가 요구사항

blackmilktea 2024. 5. 29. 03:37

퍼즐 게임 명세서의 추가 기능 구현해 보기

1. 난이도 선택

요구사항

  • 3x3 뿐만 아니라 4x4, 5x5 등의 다양한 형태의 게임 옵션 구성

4x4 예시

clip-path나 canvas로 원본 이미지를 잘라서 출력하려고 했는데 생각보다 많은 처리가 필요해서 그냥 미리 4x4, 5x5로 나눠놓은 로컬 파일을 로드하기로 했다.

function loadPuzzleImages() {
    while(puzzleContainer.firstChild)
        puzzleContainer.removeChild(puzzleContainer.firstChild)
    gameData.changeOriginalImageSet()
    gameData.generateImageIndexes()

    for (let i = 0; i < gameData.splitNum; i++) {
        for (let j = 0; j < gameData.splitNum; j++) {
            let index = i * gameData.splitNum + j
            const div = createImageContainer(gameData.imageSet,
                gameData.imageIndexesArray[index],
                gameData.level)
            div.id = index + 1
            div.addEventListener('click', handleClick)
            puzzleContainer.appendChild(div)
        }
    }
}

loadPuzzleImaes()에서 항상 자식 요소를 삭제하고 다시 만들어서 startButton과 changeImageButton에서 모두 호출해도 상관없도록 수정

2. 움직인 횟수 표시

요구사항

  • 몇 번의 움직임으로 조각난 이미지를 최종 완성 했는지를 체크
// utils.js
function swapElements(element1, element2) {
    // gameData.previouslySelectedElement -> element1
    // currentElement -> element2
    const parent1 = element1.parentNode
    const parent2 = element2.parentNode

    parent1.removeChild(element1)
    parent2.removeChild(element2)

    parent1.appendChild(element2)
    parent2.appendChild(element1)
    count++
}

swapElements가 호출되면 이미지 두 개를 선택해서 위치를 변경했다는 뜻이므로

호출될 때마다 움직임 카운팅

3. 퍼즐 완성 알림

요구사항

  • 사용자가 퍼즐을 완성하면 완성 메시지와 함께 움직인 횟수, 소요 시간 등의 정보를 표시
  • 메인 페이지로 돌아가거나 새 게임을 시작할 수 있는 옵션을 제공

완성 여부를 확인하기 위해 위에 코드에서 image-container에 미리 id 추가해 두었다.

순서가 일치할 때
순서가 섞여있을 때

 

image-container의 id와 image번호가 일치할 때 퍼즐을 완성한 것으로 판단하고

움직인 횟수와 소요 시간 출력

// puzzle 완성 여부 확인
function checkPuzzle() {
    const imageContainers = document.querySelectorAll('.image-container')
    let flag = true
    imageContainers.forEach((node) =>{
        const img = node.querySelector("img")
        // match(/\d+/g) -> 숫자 1개 이상으로 이루어진 문자열들 반환
        // 마지막 요소가 image 번호
        const imgNumber = img.src.match(/\d+/g).reverse()[0]
        if (node.id != imgNumber) flag = false;
    })
    return flag;
}
export function handleClick(event) {
    // ...
        if (checkPuzzle()) {
            endTime = new Date().getTime()
            let timeTaken = Math.floor((endTime - startTime)/1000)
            sleep(100)
                .then(() => alert(`움직인 횟수: ${count}, 소요 시간: ${timeTaken}초`))
                .then(() => count = 0, startTime = null)
        }
}
function sleep(ms) {
    return new Promise((func) => setTimeout(func, ms));
}

소요 시간은 퍼즐을 처음으로 클릭했을 때부터 시간을 체크했고,

퍼즐을 다 완성했을 때 화면이 랜더링 되기 전에 알림이 떠서 sleep함수로 잠깐 딜레이를 줬다.

메인 화면으로 돌아갈 수 있는 시작하기 버튼은 start-screen과 game-screen의 hide를 반대로 적용해 구현

새 게임을 시작할 수 있는 버튼은 이미지 교체하기 버튼으로 충분한 것 같아서

같은 그림을 다시 맞춰볼 수 있는 다시하기 버튼으로 만들었다. 

4. 사용자 편의 기능

요구사항

  • 새로고침을 하더라도 기존에 맞춰 놓은 퍼즐 정보가 유지되는 기능

+ 세션 스토리지에 원본 이미지 번호와 퍼즐 순서, 움직인 횟수, 시작 시간을 저장하고 load 시도해 볼 예정

5. 제한 시간 추가

요구사항

  • 제한 시간을 추가하여 해당 시간 내에 마무리하지 못한 경우는 '실패'라는 메시지가 뜨고 더 이상 퍼즐을 맞출 수 없도록 화면 전체를 비활성화하는 기능

+ 이미지가 있는 image-container에 등록된 이벤트를 제거해 비활성화 시도