简体   繁体   中英

Restart Simon Game in javascript

How I can make the game restart from the beginning by clicking start button except reloading the whole page?
The problem occurs because when user clicks Start playGame function is called, but the a previous instance of playGame function is still running. I even thought about to kill a previous instance of function but in JS it can not be implemented except using webworker.terminate().
Here's the code:

 document.addEventListener("DOMContentLoaded", function() { 'use strict'; var checkOn = document.querySelector("input[type=checkbox]"); var gameCount = document.getElementsByClassName("innerCount")[0]; var startButton = document.getElementById("innerStart"); var strictButton = document.getElementById("strictButton"); var strictInd = document.getElementById("strictIndicator"); var strictMode = false; var soundArray = document.getElementsByTagName("audio"); var buttons = document.querySelectorAll(".bigButton"); var buttonArray = [].slice.call(buttons, 0); checkOn.addEventListener("change", function() { if (checkOn.checked) { gameCount.innerHTML = "--"; } else { gameCount.innerHTML = ""; } }); strictButton.addEventListener("click", function() { if (checkOn.checked) { strictMode = !strictMode; strictMode ? strictInd.style.backgroundColor = "#FF0000" : strictInd.style.backgroundColor = "#850000"; } }); function getRandArray() { var array = []; for (var i = 0; i < 22; i++) { array[i] = Math.floor(Math.random() * 4); } return array; } startButton.addEventListener("click", function() { if (checkOn.checked) { var level = 0; var randIndexArr = getRandArray(); sleep(700).then(function() { playGame(randIndexArr, level); }); } }); function sleep(time) { return new Promise(resolve => { setTimeout(resolve, time) }) } function checkButton(randIndexArr, counter) { var indexButton = 0; var checker = function checker(e) { var clickedButtonId = e.target.dataset.sound; lightenButton(clickedButtonId); if (+(clickedButtonId) === randIndexArr[indexButton]) { if (indexButton === counter) { counter++; for (let i = 0; i < 4; i++) { buttonArray[i].removeEventListener("click", checker, false) } sleep(2000).then(function() { playGame(randIndexArr, counter); }); } indexButton++; } else { gameCount.innerHTML = "--"; if (strictMode) { indexButton = 0; counter = 0; } else { indexButton = 0; } for (let i = 0; i < 4; i++) { buttonArray[i].removeEventListener("click", checker, false) } sleep(2000).then(function() { playGame(randIndexArr, counter); }); } }; for (var i = 0; i < 4; i++) { buttonArray[i].addEventListener("click", checker, false) } } function playGame(randIndexArr, counter) { if (counter === 22) { return; } //Show the level of the Game gameCount.innerHTML = counter + 1; //Light and play user's input then check if input is correct randIndexArr.slice(0, counter + 1).reduce(function(promise, div, index) { return promise.then(function() { lightenButton(div); return new Promise(function(resolve, reject) { setTimeout(function() { resolve(); }, 1000); }) }) }, Promise.resolve()).then(function() { checkButton(randIndexArr, counter); }); } function lightenButton(id) { var lightColorsArr = ["liteGreen", "liteRed", "liteYell", "liteBlue"]; soundArray[id].play(); buttonArray[id].classList.add(lightColorsArr[id]); sleep(500).then(function() { buttonArray[id].classList.remove(lightColorsArr[id]) }); } }); 
 @font-face { font-family: myDirector; src: url('https://raw.githubusercontent.com/Y-Taras/FreeCodeCamp/master/Simon/fonts/myDirector-Bold.otf'); } body { background-color: #5f5f5f; } #outerCircle { display: flex; flex-wrap: wrap; margin: 0 auto; width: 560px; border: 2px dotted grey; position: relative; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } .bigButton { height: 250px; width: 250px; border: solid #464646; transition: all 1s; -webkit-transition: all 1s; -moz-transition: all 1s; -o-transition: background-color 0.5s ease; } #greenButton { background-color: rgb(9, 174, 37); border-radius: 100% 0 0 0; border-width: 20px 10px 10px 20px; } .liteGreen#greenButton { background-color: #86f999; } #redButton { background-color: rgb(174, 9, 15); border-radius: 0 100% 0 0; border-width: 20px 20px 10px 10px; } .liteRed#redButton { background-color: #f9868a; } #yellowButton { background-color: rgb(174, 174, 9); border-radius: 0 0 0 100%; border-width: 10px 10px 20px 20px; } .liteYell#yellowButton { background-color: #f9f986; } #blueButton { background-color: rgb(9, 37, 174); border-radius: 0 0 100% 0; border-width: 10px 20px 20px 10px; } .liteBlue#blueButton { background-color: #8699f9; } div#innerCircle { border: 15px solid #464646; border-radius: 50%; position: absolute; top: 25%; right: 25%; background-color: #c4c7ce; } div.additionalBorder { margin: 4px; border-radius: 50%; height: 242px; width: 242px; overflow: hidden; } p#tradeMark { margin: auto; height: 104px; text-align: center; font-size: 68px; font-family: myDirector; color: #c4c7ce; background-color: black; border-color: antiquewhite; line-height: 162px; } span#reg { font-size: 12px; } .partition { height: 6px; } .buttons { height: 128px; border-radius: 0 0 128px 128px; border: 2px solid black; } /* Start and Strict buttons*/ table { margin-left: 5px; } td { text-align: center; width: auto; padding: 2px 10px; vertical-align: bottom; } div.innerCount { width: 54px; height: 40px; background-color: #34000e; color: crimson; border-radius: 11px; font-size: 28px; line-height: 42px; text-align: center; font-family: 'Segment7Standard', italic; } button#innerStart { width: 27px; height: 27px; border: 4px solid #404241; border-radius: 50%; background: #a50005; box-shadow: 0 0 3px gray; cursor: pointer; } div.strict { display: flex; flex-direction: column; justify-content: center; align-items: center; } button#strictButton { width: 27px; height: 27px; border: 4px solid #404241; border-radius: 50%; background: yellow; box-shadow: 0 0 3px gray; cursor: pointer; } div#strictIndicator { width: 6px; height: 6px; margin-bottom: 2px; background-color: #850000; border-radius: 50%; border: 1px solid #5f5f5f; } #switcher { display: flex; justify-content: center; align-items: center; } .labels { font-family: 'Roboto', sans-serif; margin: 4px; } /* toggle switch */ .checkbox > input[type=checkbox] { visibility: hidden; } .checkbox { display: inline-block; position: relative; width: 60px; height: 30px; border: 2px solid #424242; } .checkbox > label { position: absolute; width: 30px; height: 26px; top: 2px; right: 2px; background-color: #a50005; cursor: pointer; } .checkbox > input[type=checkbox]:checked + label { right: 28px; } 
 <div id="outerCircle"> <div class="bigButton" id="greenButton" data-sound="0"> <audio src="https://s3.amazonaws.com/freecodecamp/simonSound1.mp3"></audio> </div> <div class="bigButton" id="redButton" data-sound="1"> <audio src="https://s3.amazonaws.com/freecodecamp/simonSound2.mp3"></audio> </div> <div class="bigButton" id="yellowButton" data-sound="2"> <audio src="https://s3.amazonaws.com/freecodecamp/simonSound3.mp3"></audio> </div> <div class="bigButton" id="blueButton" data-sound="3"> <audio src="https://s3.amazonaws.com/freecodecamp/simonSound4.mp3"></audio> </div> <div id="innerCircle"> <div class="additionalBorder"> <p id="tradeMark">simon<span id="reg">&reg;</span> </p> <div class="partition"></div> <div class="buttons"> <table> <tr class="firstRow"> <td> <div class="innerCount"></div> </td> <td> <button type="button" id="innerStart"></button> </td> <td> <div class="strict"> <div id="strictIndicator"></div> <button type="button" id="strictButton"></button> </div> </td> </tr> <tr class="labels"> <td> <div id="countLabel">COUNT</div> </td> <td> <div id="startLabel">START</div> </td> <td> <div id="strictLabel">STRICT</div> </td> </tr> </table> <div id="switcher"> <span class="labels">ON</span> <div class="checkbox"> <input id="checkMe" type="checkbox"> <label for="checkMe"></label> </div> <span class="labels">OFF</span> </div> </div> </div> </div> </div> 

I didn't dig super deep into your code, but it looks like the crux of it is you're using setTimeout() , and that timeout may still be running when you restart.

What you need to do is store the return value of setTimeout() which is actually an id you can then pass to clearTimeout() , which will stop that timeout.

So, on your sleep() function, store the id:

function sleep(time) {
   return new Promise(resolve => {
     this.timeoutId = setTimeout(resolve, time)
   });
}

And when you go to restart your game:

// ...
if (this.timeoutId) {
    clearTimeout(this.timeoutId);
    this.timeoutId = null;
}
//...

And then also just make sure you don't have any other code that will get more than two timeouts running at the same time (or you'll lose one of the ids).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM