Juan Juan - 3 months ago 17
Javascript Question

Simon game javascript, how do I synchronize the lights of the buttons not to step on each other with animation() and delay() JQUERY?

I'm doing a Simon game and I'm taking the opacity from 1 to 0.3 and back to 1 everytime a sequence has place. It's almost working but the case that gives problem is when in the sequence I have the same color in a row. GREEN, GREEN, RED, BLUE for example displays just one green press and one red and one blue. It's a problem with the timing cause the logic works fine. Here's my code

$(document).ready(function(){


let simon={
colors:["green","red","yellow","blue"],
sequence:[],
userSequence:[],
strict:false,
buttonSounds : {},
init: function(){
let objectContext=this;


$("#start").on("click",function(){

objectContext.setSounds();


//executes for the first time
objectContext.emptyAllSequences();
//I generate the first of the sequence
objectContext.generateAndAddRandomColor();
//I display the sequence on the board
objectContext.displaySequenceOnBoard();


});

$("#title").addClass('tada animated');

$("#strict").on("click",function(){
$(this).toggleClass("active");

if($(this).hasClass("active")){
objectContext.strict=true;
}else{
objectContext.strict=false;
}

});

$(".button").on("click",function(){
const color=$(this).attr("data-color");
objectContext.lightButton(color,0);
objectContext.userSequence.push(color);


let isSequenceCorrect=objectContext.checkUserSequence();

/* console.log("sequenceCorrect "+isSequenceCorrect);
console.log("sequence "+objectContext.sequence);
console.log("user sequence "+objectContext.userSequence);
console.log("user sec length "+objectContext.userSequence.length);
console.log("sec length "+objectContext.sequence.length);*/
if(objectContext.userSequence.length===objectContext.sequence.length || !isSequenceCorrect){

if(isSequenceCorrect){
setTimeout(function(){objectContext.generateAndAddRandomColor();
objectContext.displaySequenceOnBoard();
//reset the userSequence to check the whole sequence again
objectContext.emptyUserSequence(); }, 1500);
}else{

//if strict mode is on
if(strict){
//user looses
$("#count").html("Lost");
//wipe sequence array
objectContext.emptyAllSequences();
$("#start").removeClass("active");
}else{

setTimeout(function(){
//change this to generate another sequence instead of displaying the existent
objectContext.displaySequenceOnBoard();
//reset the userSequence to check the whole sequence again
objectContext.emptyUserSequence(); }, 1500);



}
}
}
});

},
setSounds:function(){

this.buttonSounds["green"] = new Audio("https://s3.amazonaws.com/freecodecamp/simonSound1.mp3");
this.buttonSounds["red"] = new Audio("https://s3.amazonaws.com/freecodecamp/simonSound2.mp3");
this.buttonSounds["yellow"] = new Audio("https://s3.amazonaws.com/freecodecamp/simonSound3.mp3");
this.buttonSounds["blue"] = new Audio("https://s3.amazonaws.com/freecodecamp/simonSound4.mp3");

},

emptyUserSequence: function(){
this.userSequence.length=0;
},

emptyAISequence: function(){
this.sequence.length=0;
},

emptyAllSequences:function(){
this.emptyUserSequence();
this.emptyAISequence();
},
updateCount: function(){
$("#count").html(this.sequence.length);

},

checkUserSequence:function(){

for(let i=0,len=this.userSequence.length;i<len;i++){

if(this.userSequence[i]!== this.sequence[i]){
return false;
}

}


return true;
},

generateAndAddRandomColor:function(){

const randColorIndex=Math.floor(Math.random()*4);


const randColor=this.colors[randColorIndex];
this.sequence.push(randColor);
this.updateCount();

},

displaySequenceOnBoard: function(){

for(let i=0,len=this.sequence.length;i<len;i++){

// this.buttonSounds[this.sequence[i]].play();
this.lightButton(this.sequence[i],i);


}//end for
},
lightButton: function(color,i){

var objectContext=this;

$("#"+color).delay(400*i)
.animate({opacity : 0.3}, 300,function(){

objectContext.buttonSounds[color].play();
$("#"+color).animate({opacity : 1}, 150);


});


}
}
simon.init();
});


Here's the codepen. You have to press start to start the game and as the sequence grows and is displayed on the board the problem commented before arises, what could be happening?. Thanks!

http://codepen.io/juanf03/pen/jrEdWz?editors=1111

Answer

You're setting multiple delays on the same element at once, and the newest one just replaces the existing one.

Instead of using delays, pass a complete function with your animation, and give it the whole remaining sequence. To illustrate, replace your current displaySequenceOnBoard() with these two functions:

  displaySequenceOnBoard: function(){
    $(".button").removeClass("enabled");
    this.lightButtonsInSequence(this.sequence);

  },

  lightButtonsInSequence: function(sequence) {
    var color = sequence[0]
    var remainingSequence = sequence.slice(1)
    var lightNextButtonFunction = remainingSequence.length > 0 ? jQuery.proxy(function(){
                this.lightButtonsInSequence(sequence.slice(1));
              }, this) : null;
    console.log("Lighting color: " + color);
    $("#"+color).animate({opacity : .3}, 300).animate({opacity : 1}, 150, lightNextButtonFunction)

  }

Here it is plugged into your CodePen and working.