2016-11-09 140 views
0

如何通過點擊開始按鈕來重新啓動遊戲,除了重新加載整個頁面?
問題發生的原因是當用戶點擊開始 playGame函數被調用,但playGame函數的前一個實例仍在運行。我甚至想過要殺掉以前的函數實例,但在JS中,除了使用webworker.terminate()之外,它不能實現。
下面的代碼:用javascript重新啓動西蒙遊戲

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>

+0

設置一個跟蹤遊戲開/關狀態的模塊布爾變量(通過開/關按鈕的點擊事件設置)以及下一個按鈕序列生成的代碼段中,變量? –

+0

@ScottMarcus謝謝您使用您的建議,但在此之前,我必須更改代碼以創建一些私有變量的全局變量。 –

回答

0

我沒有挖超深到你的代碼,但它看起來像它的關鍵是你使用setTimeout(),而且超時可能仍在重新啓動時運行。

你需要做的是存儲返回值setTimeout(),這實際上是一個ID,然後你可以傳遞給clearTimeout(),這將停止超時。

所以,在你的sleep()功能,存儲ID:

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

而當你去重新啓動遊戲:

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

然後還只是確保你沒有任何其他代碼將會同時運行超過兩個超時(或者您將失去其中一個ID)。