2015-09-25 102 views
3

我正在用jQuery製作一個Simon的小遊戲。我有我想要的功能;開始在網頁加載,分數,整數等,並在一定程度上游戲的作品。jQuery記憶技能遊戲setTimeout()問題

但是,我仍然有一個問題,我無法擺脫困境。我希望能夠防止用戶在計算機上選擇面板。目前,用戶可以在計算機顯示其輸出時觸發序列,這會導致按鈕閃爍和聲音混亂。

問題出在setTimeout()。我試圖實現一個變量'cpuLoop',在計算機輪到時變成true,然後返回false,但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 
}); 

});

here is a link to the app on codepen。非常感謝

回答

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函數可以保證它們全部被清除。

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(); 
    } 
}