我正在使用jQuery进行Simon的小游戏。我有我想要的功能;从页面加载,得分,数字等开始,游戏在一定程度上起作用。
然而,我仍然有一个问题,我无法理解。我希望能够阻止用户在计算机转换过程中选择面板。目前,用户可以在计算机显示其输出期间触发序列,这会导致按钮闪烁和声音熄灭造成严重破坏。
问题在于setTimeout()
。我试图实现一个变量' cpuLoop'在计算机转向时变为真,然后变回假,但setTimeout()
的实现意味着即使在cpuLoop
之后仍然存在事件循环上的事件已被改为假。如果更改为false会立即改变,当然它应该等到setTimeout()
完成。
单击重置按钮时会遇到类似的问题。单击时,它应该中断setTimeout()
事件并重新启动游戏。事实上,它继续输出电脑。
为了解决这个问题,我已将setTimeout()
函数附加到全局范围内,并尝试使用clearInterval(var)
删除它们,但这似乎暂时没有效果。
这是我的jQuery:
$(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
});
});
答案 0 :(得分:1)
你的问题是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
调用结束时减少它,并且只有在计数器是的时候调用second_part
函数。 0:
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();
}
}
答案 1 :(得分:1)
这似乎对我来说在计算机转动过程中禁用用户输入是正常的:
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
函数可以保证它们都被清除。