JavaScript实现Simon游戏时数组长度异常翻倍问题求助
解决Simon游戏中roundList数组长度异常翻倍问题
问题根源
你的roundList数组长度翻倍的核心原因是nextRound函数的逻辑错误:
- 用
setInterval调用randomColor,次数等于当前roundList的长度,但randomColor每次执行都会向roundList中添加新元素,导致数组长度随着每次调用持续增加,最终执行次数超过预期,数组长度翻倍。 setTimeout(repeat, delay)是错误用法,setTimeout的第一个参数必须是函数,传入定时器ID会引发意外行为。check函数仅验证用户输入是否等于最后一个元素,没有跟踪用户输入的步骤,不符合Simon游戏的规则(需要依次匹配整个序列)。
修复方案
- 拆分函数职责:将生成新颜色和播放颜色动画的逻辑分离,避免重放序列时误添加新元素。
- 修正
nextRound逻辑:重放已有序列后,再添加一个新的随机颜色,而不是在重放过程中添加新元素。 - 修复
check函数:跟踪用户当前输入的步骤索引,依次验证每个输入是否匹配序列中的对应位置。 - 移除错误的
setTimeout调用:正确控制定时器的启动和停止。
完整修复后的代码
JavaScript
var audioContext = new AudioContext(); function playFrequency(frequency) { var sampleRate = audioContext.sampleRate; var duration = sampleRate / 2.5; var numChannels = 1; var buffer = audioContext.createBuffer(numChannels, duration, sampleRate); var channelData = buffer.getChannelData(0); for (var i = 0; i < duration; i++) { channelData[i] = Math.sin(2 * Math.PI * frequency * i / sampleRate); } var source = audioContext.createBufferSource(); source.buffer = buffer; source.connect(audioContext.destination); source.start(0); } let A = document.getElementById('green'); let B = document.getElementById('red'); let C = document.getElementById('blue'); let D = document.getElementById('yellow'); function reset(color) { switch(color) { case 'green': A.style.backgroundColor = '#3f3'; A.style.boxShadow = '0 0 0 0'; break; case 'red': B.style.backgroundColor = "#f33"; B.style.boxShadow = '0 0 0 0'; break; case 'blue': C.style.backgroundColor = "#33f"; C.style.boxShadow = "0 0 0 0"; break; case 'yellow': D.style.backgroundColor = "#ff3"; D.style.boxShadow = '0 0 0 0'; break; } } // 播放单个颜色的动画和声音(不添加到序列) function playColor(color) { switch(color) { case 'green': A.style.backgroundColor = '#8f8'; A.style.boxShadow = '0 0 20px #8f8'; playFrequency(440); setTimeout(() => reset('green'), 400); break; case 'red': B.style.backgroundColor = '#f88'; B.style.boxShadow = '0 0 20px #f88'; playFrequency(554.3653); setTimeout(() => reset('red'), 400); break; case 'blue': C.style.backgroundColor = '#88f'; C.style.boxShadow = '0 0 20px #88f'; playFrequency(659.2551); setTimeout(() => reset('blue'), 400); break; case 'yellow': D.style.backgroundColor = '#ff8'; D.style.boxShadow = '0 0 20px #ff8'; playFrequency(880); setTimeout(() => reset('yellow'), 400); break; } } let roundList = []; const colors = ['green', 'red', 'blue', 'yellow']; let currentStep = 0; // 跟踪用户当前输入的步骤 let score = 0; let scoreText = document.getElementById('score'); scoreText.innerText = `Score: ${score}`; // 生成新随机颜色并添加到序列 function generateNewColor() { const randomIndex = Math.floor(Math.random() * 4); const newColor = colors[randomIndex]; roundList.push(newColor); return newColor; } // 重放整个序列 function replaySequence() { currentStep = 0; roundList.forEach((color, index) => { setTimeout(() => playColor(color), 600 * index); }); // 重放结束后等待用户输入 setTimeout(() => enableInput(), 600 * roundList.length); } function startGame() { roundList = []; score = 0; scoreText.innerText = `Score: ${score}`; disableInput(); const firstColor = generateNewColor(); setTimeout(() => playColor(firstColor), 500); setTimeout(() => enableInput(), 1000); } function check(input) { disableInput(); playColor(input); // 播放用户点击的动画 if (input === roundList[currentStep]) { currentStep++; if (currentStep === roundList.length) { // 用户完成当前序列,进入下一轮 score++; scoreText.innerText = `Score: ${score}`; setTimeout(() => nextRound(), 1000); } else { enableInput(); } } else { scoreText.innerText = "you lose"; } } function nextRound() { disableInput(); generateNewColor(); replaySequence(); } // 禁用/启用用户输入,避免重复点击 function disableInput() { document.querySelectorAll('.input-btn').forEach(btn => btn.disabled = true); } function enableInput() { document.querySelectorAll('.input-btn').forEach(btn => btn.disabled = false); }
CSS
* { max-width: 1920px; max-height: 1080px; overflow-x: hidden; overflow-y: hidden; } #row1 { height: 400px; } .square { width: 100px; height: 100px; } #green { background-color: #33ff33; } #red { background-color: #ff3333; } #blue { background-color: #3333ff; } #yellow { background-color: #ffff33; } .buttonbox { width: 100%; } .input-btn { margin: 0; height: 100%; width: 100%; cursor: pointer; } #greenbtn { background-color: inherit; border: none; } #redbtn { background-color: inherit; border: none; } #bluebtn { background-color: inherit; border: none; } #yellowbtn { background-color: inherit; border: none; } #start, #score { width: 100px; display: block; }
HTML
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <div class="simon"> <div class="row" id="row1"></div> <div class="row"> <div class="col col-xxl-4"></div> <div class="col col-xxl-1"> <div class="square mx-auto" id="green"> <button class="input-btn" id="greenbtn" onclick="check('green')"></button> </div> </div> <div class="col col-xxl-1"> <div class="square mx-auto" id="red"> <button class="input-btn" id="redbtn" onclick="check('red')"></button> </div> </div> <div class="col col-xxl-1"> <div class="square mx-auto" id="blue"> <button class="input-btn" id="bluebtn" onclick="check('blue')"></button> </div> </div> <div class="col col-xxl-1"> <div class="square mx-auto" id="yellow"> <button class="input-btn" id="yellowbtn" onclick="check('yellow')"></button> </div> </div> <div class="col col-xxl-4"></div> </div> <br> <div class="row"> <div class="col col-xxl-4"></div> <div class="col col-xxl-4"> <button id="start" onclick="startGame()" class="mx-auto">Start Game</button> </div> <div class="col col-xxl-4"></div> </div> <br> <div class="row"> <div class="col col-xxl-4"></div> <div class="col col-xxl-4"> <p id="score" class="mx-auto text-center"></p> </div> <div class="col col-xxl-4"></div> </div> </div>
关键修复点说明
- 拆分出
playColor负责播放动画,generateNewColor负责生成新元素,重放序列时不再向roundList添加元素。 - 添加
currentStep跟踪用户输入进度,确保用户依次匹配序列中的每个元素。 - 加入
enableInput/disableInput函数,避免用户在序列播放期间重复点击。 nextRound现在先添加新元素,再重放整个序列,符合Simon游戏的规则。
内容的提问来源于stack exchange,提问作者Seychelles
相关产品推荐
相关产品推荐

