[Javascript] 숫자기억게임 만들기

최종 결과

 

구현 목표

1) 시작버튼 클릭시 1000~9999 사이의 숫자가 무작위로 나타나고, 3초 뒤 사라진다.

2) 사용자가 숫자를 입력하고, 제출 버튼을 통해 정답 유무를 확인한다.

3) 정답일시 "정답입니다!" 오답일시 "오답입니다! 정답은 nnnn입니다."를 노출한다.

4) 그 외 자유!

 

추가한 기능

1) 숫자가 보여지는 동안 입력 및 제출 제한, 사용자가 입력한 정답은 다시 게임을 시작할 때 지워주기

2) 정답 제출 후 2초 뒤 초기화

3) 제한시간(3초) 카운트다운 보이기

4) 입력 필드에 안내문구 표시

 

 

setTimeout 활용 오류

거의 끝났다 생각하고 즐겁게 테스트를 해보던 중.. 내가 외워야하는 숫자가 바뀌고 카운트다운도 멈추는 상황을 발견했다.

 

의심가는 곳에 중단점을 찍어보다가 화면 구성을 초기화하는 함수가 실행되며 이러한 현상이 나타난다는 것을 깨달았고,

어떤 곳에서 해당 기능이 호출되고 있는지 되짚어보았다.

 

원인

게임을 다시 시작할 수 있도록 화면 구성을 되돌리는 것은 두가지 방법에 의해 실행됐다.

1) 정답 제출 후 2초 후 자동으로

2) 다시 시작버튼을 눌렀을 때

 

정답을 제출했을 때 시작된 타이머가 게임을 다시 시작한 후에도 흐르고있어 문제가 생긴 것이다.

 

해결

자동 초기화를 위한 타이머를 시작할 때 타이머ID를 변수에 받고, 게임을 시작할 때 clearTimeout으로 타이머 초기화를 포함시켰다!

function initTimer() {
    clearTimeout(resetTimer);  // 추가한 부분
    lefttime = TIME_LIMIT;
    $('#lefttime').text(lefttime);
    clearInterval(countdownTimer);
}

function initGame() {
    initTimer();
    $('#userinput').val("");
    $('#userinput').attr("placeholder", "시작버튼을 눌러주세요!");
    $('#userinput').attr("disabled", true);
    $('#submitbutton').attr("disabled", true);
    $('#answer').empty();
}

function checkanswer() {
	userInput = $('#userinput').val();
	if (userInput == answer) {
		$('#answer').text("정답입니다!");
	}
	else {
		$('#answer').text(`오답입니다! 정답은 ${answer}입니다.`);
	}

	// 2초 뒤 게임 초기화
	resetTimer = setTimeout(initGame, 2000);
}

 

오늘의 교훈.. 

타이머를 사용했다면 꼭 꺼주자!!

 

 

전체 코드

1) HTML

<body>
    <div class="mainbox">
        <div class="title moirai-one-regular">
            <h1>숫자기억게임</h1>
        </div>
        <div class="numbercontainer">
            <h2 id="number"></h2>
        </div>
        <div class="countdown">
            <h2 id="lefttime" hidden></h2>
        </div>
        <div class="inputcontainer">
            <input type="text" id="userinput" placeholder="시작버튼을 눌러주세요!" disabled>
            <button id="startbutton" onclick="start()">시작</button>
            <button id="submitbutton" onclick="checkanswer()" disabled>제출</button>
        </div>
        <div class="answercontainer">
            <h2 id="answer"></h2>
        </div>
    </div>
</body>

 

2) CSS

@import url('https://fonts.googleapis.com/css2?family=Hahmlet:wght@100..900&family=Moirai+One&family=Nanum+Gothic&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Hahmlet:wght@100..900&family=Moirai+One&family=Nanum+Gothic&family=Noto+Sans+KR:wght@100..900&display=swap'

.moirai-one-regular {
    font-family: "Moirai One", system-ui;
    font-weight: 400;
    font-style: normal;
}

* {
    padding: 0;
    margin: 0;
    border: none;
}

html {
    height: 100%;
}

body {
    height: 100%;
    background-color: lightgrey;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    font-family: "Noto Sans KR", sans-serif;
    font-optical-sizing: auto;
    font-weight: normal;
    font-style: normal;
}

.mainbox {
    background-color: white;
    width: 40%;
    height: 30%;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    border-radius: 8px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.title {
    text-align: center;
    font-size: 1.5rem;
    width: 300px;
    margin-top: 30px;
}

.inputcontainer {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    width: 500px;
    margin-top: 15px;
}

.inputcontainer>input {
    height: 30px;
    width: 50%;
    border: 1px solid black;
    border-radius: 3px;
    padding-left: 10px;
    margin-right: 10px;
}

.inputcontainer>button {
    margin-right: 10px;
    height: 30px;
    width: 10%;
    border: 1px solid black;
    border-radius: 3px;
    background-color: lightgrey;
    font-weight: bold;
}

.numbercontainer {
    width: 300px;
    height: 35px;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    margin-top: 10px;
}

.answercontainer {
    text-align: center;
    height: 35px;
    margin-top: 15px;
}

.countdown {
    color: rgb(255, 48, 48);
    height: 35px;
    text-align: center;
}

 

3) JS

const TIME_LIMIT = 3;
let lefttime;
let countdownTimer;

function initTimer() {
    clearTimeout(resetTimer);
    lefttime = TIME_LIMIT;
    $('#lefttime').text(lefttime);
    clearInterval(countdownTimer);
}

function initGame() {
    initTimer();
    $('#userinput').val("");
    $('#userinput').attr("placeholder", "시작버튼을 눌러주세요!");
    $('#userinput').attr("disabled", true);
    $('#submitbutton').attr("disabled", true);
    $('#answer').empty();
}

const MIN_NUMBER = 1000;
const MAX_NUMBER = 9999;
let answer = 0;
function start() {
    initGame();
    $('#lefttime').attr("hidden", false);
    answer = Math.floor(Math.random() * (MAX_NUMBER - MIN_NUMBER + 1) 
    $('#number').text(answer);
    $('#userinput').attr("placeholder", "숫자를 외우세요!");
    countdownTimer = setInterval(countdown, 1000);
}

function hideAnswer() {
    $('#number').empty();
    $('#userinput').attr("disabled", false);
    $('#submitbutton').attr("disabled", false);
    $('#userinput').attr("placeholder", "정답을 입력해주세요!");
}

let userInput = 0;
let resetTimer;
function checkanswer() {
    userInput = $('#userinput').val();
    if (userInput == answer) {
        $('#answer').text("정답입니다!");
    }
    else {
        $('#answer').text(`오답입니다! 정답은 ${answer}입니다.`);
    }
    // 2초 뒤 게임 초기화
    resetTimer = setTimeout(initGame, 2000);
}

function countdown() {
    lefttime --;
    $('#lefttime').text(lefttime);
    if(lefttime <= 0) {
        clearInterval(countdownTimer);
        $('#lefttime').attr("hidden", true);
        hideAnswer();
    }
}

'프로젝트 > 개인 과제' 카테고리의 다른 글

TODO-LIST 만들기  (0) 2024.07.05
한식메뉴 렌더링하기  (0) 2024.06.26