jQuery Memory Skill游戏setTimeout()问题

时间:2015-09-25 14:49:42

标签: javascript jquery

我正在使用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
});

});

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

2 个答案:

答案 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函数可以保证它们都被清除。