1

I am building a Simon game, and have built a function for each new round as so:

var game = [];
var squares = ["green", "red", "blue", "yellow"];

var newRound = function() {
  // adds a new round to the end of the game array
  game.push(squares[Math.floor(Math.random() * squares.length)]);

  // for loop to run through the game array
  for (var x = 0; x < game.length; x++) {
    playButton(game[x]);
  }
}

Then, I built another function which controls the animation and sound for each time the square is either hit by a user, or cycled through my for-loop

var playButton = function(color){
  $("#"+color).addClass(color+"--active active", 300, function(){
     $("#audio-"+color).trigger('play');
     $("#"+color).removeClass(color+"--active active", 300)
});

Right now, my for-loop just cycles through all the animations and sounds in one go. How can I make the for-loop wait for the playButton function to finish execution before cycling through again?

code sample on CodePen

nem035
  • 34,790
  • 6
  • 87
  • 99
lfkwtz
  • 1,007
  • 2
  • 11
  • 25

2 Answers2

5

You can convert your for loop into a recursive function that plays the current button and then tries to play the next button after all animations are done. Something like:

var newRound = function() {
  // adds a new round to the end of the game array
  game.push(squares[Math.floor(Math.random() * squares.length)]);

  // start playing from the first button
  playButton(game, 0);
}

function playButton(game, index) {
  if (index < game.length) { // if this button exists, play it
    var color = game[index];
    $("#" + color).addClass(color + "--active active", 300, function() {
      $("#audio-" + color).trigger('play');
      $("#" + color).removeClass(color + "--active active", 300, function() {
        playButton(game, index + 1); // once this button was played, try to play the next button
      });
    });
  }
}
nem035
  • 34,790
  • 6
  • 87
  • 99
  • This is a great solution, thanks. A weird bug occurs though when a single button is pressed twice in a row, the sound only plays the first time. I increased the milliseconds to 400 and that no longer happens. Any idea why? – lfkwtz Nov 05 '15 at 20:29
  • 1
    No problem, glad to help. As for your question, you need to decide how you want to handle allowing the user to click on things **while they are animating**. If you want to ignore their clicks while an animation is in progress, an easy fix would be to add a flag, for example, `isAnimating` that is initialized to `false`. Then, in your `click` handler, if this flag is `false`, you start the animation, then you set the flag to `true` and when the animation is done, set it back to `false`. This will make sure user can't start a bunch of animations with a bunch of clicks :) – nem035 Nov 05 '15 at 21:24
0

Javascript is single-threaded, so what you are asking for is already happening. However your DOM isn't updated because sometimes your DOM elements aren't there. The DOM updation is out-of-sync with your javascript.

So instead, you can execute your playButton function at set intervals.

if(x<game.length) {
   setInterval(playButton(x), <someSmallNumber like 0.2 milliseconds>);

}

Then increment x. By incrementing color, x gets incremented since it's a pass by reference.

var playButton = function(color){
     $("#"+color).addClass(color+"--active active", 300, function(){
     $("#audio-"+color).trigger('play');
     $("#"+color).removeClass(color+"--active active", 300)
     color++;
});
Divyanth Jayaraj
  • 950
  • 4
  • 12
  • 29
  • *By incrementing color, x gets incremented* this is not correct. JS is [pass-by-value](http://stackoverflow.com/questions/6605640/javascript-by-reference-vs-by-value) so `color` contains a copy of the value of `x` and updating it **doesn't affect** `x`. – nem035 Nov 05 '15 at 18:31