我正在用jQuery制作一个小游戏。我有我想要的功能;从页面加载、分数、整数等开始,游戏就能在一定程度上运行。
然而,我仍然有一个问题,我不明白。我希望能够防止用户能够在计算机的回合中选择面板。目前,用户可以在计算机显示其输出时触发一个序列,这会导致按钮闪烁和声音消失。
问题出在setTimeout()
。我试图实现一个变量"cpuLoop",当轮到计算机时变为true,然后返回false,但是setTimeout()
的实现意味着即使在cpuLoop
被更改为false之后,事件循环上仍有事件。当它应该等待setTimeout()
完成时,立即更改为false。
点击重置按钮时也会遇到类似的问题。当点击时,它应该中断setTimeout()
事件并重新开始游戏。现在,它继续输出计算机的结果。
为了解决这个问题,我在全局作用域中附加了setTimeout()
函数,并试图用clearInterval(var)
将它们切断,但这似乎目前没有效果。
$(function(){
var counter = 0;
var cpuArray = [];
var cpuSlice = [];
var numArray = [];
var userArray = [];
var num = 1;
var wins = 0;
var losses = 0;
var cpuLoop = false;
// Initialise the game
function init(){
$('#roundNumber').html('1');
counter = 0;
cpuArray = [];
numArray = [];
userArray = [];
cpuLoop = false;
num = 1;
// Create cpuArray
function generateRandomNum(min, max){
return Math.floor(Math.random() * (max - min) + min);
}
for(var i = 1; i <= 20; i++){
numArray.push(generateRandomNum(0, 4));
}
for(var i = 0; i < numArray.length; i++){
switch(numArray[i]){
case 0:
cpuArray.push('a');
break;
case 1:
cpuArray.push('b');
break;
case 2:
cpuArray.push('c');
break;
case 3:
cpuArray.push('d');
break;
}
}
console.log('cpuArray: ' + cpuArray);
// Create a subset of the array for comparing the user's choices
cpuSlice = cpuArray.slice(0, num);
goUpToPoint(cpuSlice);
}
init();
var looperA, looperB, looperC, looperD;
// Cpu plays sounds and lights up depending on cpuArray
function cpuPlayList(input, time){
setTimeout(function(){
if(input === 'a'){
looperA = setTimeout(function(){
aSoundCpu.play();
$('#a').fadeOut(1).fadeIn(500);
}, time * 500);
} else if(input === 'b'){
looperB = setTimeout(function(){
bSoundCpu.play();
$('#b').fadeOut(1).fadeIn(500);
}, time * 500);
} else if(input === 'c'){
looperC = setTimeout(function(){
cSoundCpu.play();
$('#c').fadeOut(1).fadeIn(500);
}, time * 500);
} else if(input === 'd'){
looperD = setTimeout(function(){
dSoundCpu.play();
$('#d').fadeOut(1).fadeIn(500);
}, time * 500);
}
}, 1750);
};
// CPU takes its turn
function goUpToPoint(arr){
cpuLoop = true;
console.log('cpuLoop: ' + cpuLoop);
for(var i = 0; i < arr.length; i++){
cpuPlayList(arr[i], i);
}
cpuLoop = false;
console.log('cpuLoop: ' + cpuLoop);
}
// User presses restart button
$('.btn-warning').click(function(){
clearTimeout(looperA);
clearTimeout(looperB);
clearTimeout(looperC);
clearTimeout(looperD);
init();
});
// Array comparison helper
Array.prototype.equals = function (array) {
// if the other array is a falsy value, return
if (!array)
return false;
// compare lengths - can save a lot of time
if (this.length != array.length)
return false;
for (var i = 0, l=this.length; i < l; i++) {
// Check if we have nested arrays
if (this[i] instanceof Array && array[i] instanceof Array) {
// recurse into the nested arrays
if (!this[i].equals(array[i]))
return false;
}
else if (this[i] != array[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
}
// User presses one of the four main buttons
function buttonPress(val){
console.log('strict?: ' + $('#strict').prop('checked'));
console.log('cpuSlice: ' + cpuSlice);
userArray.push(val);
console.log('userArray: ' + userArray);
if(val === 'a'){ aSoundCpu.play(); }
if(val === 'b'){ bSoundCpu.play(); }
if(val === 'c'){ cSoundCpu.play(); }
if(val === 'd'){ dSoundCpu.play(); }
// If the user selected an incorrect option
if(val !== cpuSlice[counter])
//Strict mode off
if(!$('#strict').prop('checked')){
// Strict mode off
alert('WRONG! I'll show you again...');
userArray = [];
console.log('cpuSlice: ' + cpuSlice);
goUpToPoint(cpuSlice);
counter = 0;
} else {
//Strict mode on
losses++;
$('#lossCount').html(losses);
ui_alert('You lose! New Game?');
return;
} else {
// User guessed correctly
counter++;
}
if(counter === cpuSlice.length){
$('#roundNumber').html(counter + 1);
}
if(counter === 5){
ui_alert('YOU WIN!');
$('#winCount').html(++wins);
return;
}
console.log('counter: ' + counter);
if(counter === cpuSlice.length){
console.log('num: ' + num);
cpuSlice = cpuArray.slice(0, ++num);
console.log('userArray:' + userArray);
userArray = [];
console.log('cpuSlice: ' + cpuSlice);
goUpToPoint(cpuSlice);
counter = 0;
}
}
// Button presses
$('#a').mousedown(function(){
if(!cpuLoop){
buttonPress('a');
}
});
$('#b').mousedown(function(){
if(!cpuLoop) {
buttonPress('b');
}
});
$('#c').mousedown(function(){
if(!cpuLoop){
buttonPress('c');
}
});
$('#d').mousedown(function(){
if(!cpuLoop){
buttonPress('d');
}
});
// jQuery-UI alert for when the user has either won or lost
function ui_alert(output_msg) {
$("<div></div>").html(output_msg).dialog({
height: 150,
width: 240,
resizable: false,
modal: true,
position: { my: "top", at: "center", of: window },
buttons: [
{
text: "Ok",
click: function () {
$(this).dialog("close");
init();
}
}
]
});
}
// Sound links
var aSoundCpu = new Howl({
urls: ['https://s3.amazonaws.com/freecodecamp/simonSound1.mp3'],
loop: false
});
var bSoundCpu = new Howl({
urls: ['https://s3.amazonaws.com/freecodecamp/simonSound2.mp3'],
loop: false
});
var cSoundCpu = new Howl({
urls: ['https://s3.amazonaws.com/freecodecamp/simonSound3.mp3'],
loop: false
});
var dSoundCpu = new Howl({
urls: ['https://s3.amazonaws.com/freecodecamp/simonSound4.mp3'],
loop: false
});
});
,这是codepen上的应用程序链接。非常感谢
在轮到计算机时禁用用户输入对我来说似乎工作正常:
function goUpToPoint(arr){
cpuLoop = true;
console.log('cpuLoop: ' + cpuLoop);
for(var i = 0; i < arr.length; i++){
cpuPlayList(arr[i], i);
}
//cpuLoop = false;
setTimeout(function() {
cpuLoop = false;
}, arr.length * 500 + 1750);
console.log('cpuLoop: ' + cpuLoop);
}
然后重置按钮,将它与上面的全局函数init()放在一起
timeoutsArray = [];
并编辑这些函数:
// Cpu plays sounds and lights up depending on cpuArray
function cpuPlayList(input, time){
timeoutsArray.push(setTimeout(function(){
if(input === 'a'){
timeoutsArray.push(setTimeout(function(){
aSoundCpu.play();
$('#a').fadeOut(1).fadeIn(500);
}, time * 500));
} else if(input === 'b'){
timeoutsArray.push(setTimeout(function(){
bSoundCpu.play();
$('#b').fadeOut(1).fadeIn(500);
}, time * 500));
} else if(input === 'c'){
timeoutsArray.push(setTimeout(function(){
cSoundCpu.play();
$('#c').fadeOut(1).fadeIn(500);
}, time * 500));
} else if(input === 'd'){
timeoutsArray.push(setTimeout(function(){
dSoundCpu.play();
$('#d').fadeOut(1).fadeIn(500);
}, time * 500));
}
}, 1750));
};
// User presses restart button
$('.btn-warning').click(function(){
for(var i = 0; i < timeoutsArray.length; i++) {
clearTimeout(timeoutsArray[i]);
}
timeoutsArray = [];
init();
});
我认为你正在替换一些looperX
变量值。使用一个数组来存储所有的setTimeout
函数,可以保证它们都被清除。
你的问题是setTimeout
是一个异步函数,这意味着一旦你调用它,它之后的代码继续,好像它已经完成了。
如果您希望代码等待到循环结束,则需要在setTimeout
函数的末尾调用它。
你可以把你的函数分成两部分(在你的例子中是goUpToPoint
函数),像这样:
function first_part() {
//Call setTimeout
setTimeout(function() { some_function(); }, time);
}
function second_part() {
// Rest of code...
}
function some_function() {
//Delayed code...
...
second_part();
}
由于您多次调用函数,我会创建一个全局计数器,您可以在每次setTimeout
调用结束时减少,并仅在计数器为0时调用second_part
函数:
var global_counter = 0;
function first(num) {
//Call setTimeout
global_counter = num;
for (var i = 0; i < num; i++) {
setTimeout(function() { some_function(); }, time);
}
}
function second() {
// Rest of code...
}
function some_function() {
//Delayed code...
...
// Decrease counter
global_counter--;
if (global_counter == 0) {
second();
}
}