skip to Main Content

Im new to programming and making the infamous Simon says game but I’m having trouble getting the computer generated sequence to animate in the order of the array.

I wanted to have a function that both wiped the previous sequence (assuming the game has started) and creates a new one while animating the buttons in the order of new array. I tried a few different methods but their outputs only confused me more.

var pattern       = []
var userPattern   = [];
var buttonColours = ["red", "blue", "green", "yellow"];
var started       = false
var level         = 0;

function nextSequence() {
  pattern     = [];
  userPattern = [];
  while (pattern.length < 4) {
    var randomNumber = Math.floor(Math.random() * 4);
    var randomColour = buttonColours[randomNumber];
    pattern.push(randomColour);
  }

  /*Method 1*/
  for (i = 0; i < pattern.length; i++) {
    setTimeout(function() {
      $("." + pattern[i]).fadeOut(200).fadeIn(200);
    }, 500 * (i + 1));
  }

  /*Mehtod 2*/
  // setTimeout($("." + pattern[0]).fadeOut(200).fadeIn(200), 500);
  // setTimeout($("." + pattern[1]).fadeOut(200).fadeIn(200), 1000);
  // setTimeout($("." + pattern[2]).fadeOut(200).fadeIn(200), 1500);
  // setTimeout($("." + pattern[3]).fadeOut(200).fadeIn(200), 2000);


  $("h1").html("Level" + " " + level);
  level++;
  console.log(pattern)
}

The first method doesn’t play the animation at all and the second plays the animations simultaneously completely disregaurding the setTimeout function. Method 2 also returns a Uncaught SyntaxError: Unexpected identifier ‘Object’ directed at all 4 lines of code.

3

Answers


  1. In the first method you are passing a function as parameter to the setTimeout which is fine, but by the time the i in the function gets evaluated it is already i = 4.

    The way to overcome the late evaluation of the i is to pass a copy of it that will live inside a function (IIFE). Also the rest of your code will live inside that function, where i is what was meant to be when passed to it as argument.

    /*Method 1*/
    for (i = 0; i < 4; i++) {
      (function(i) {
    
        setTimeout(function() {
          $("." + pattern[i]).fadeOut(200).fadeIn(200);
        }, 500 * (i + 1));
        
      })(i)
    }
    
    Login or Signup to reply.
  2. The problem is that the value of i is not what you expect when the setTimeout triggers its function. Just declare it using let.

    var pattern       = []
    var userPattern   = [];
    var buttonColours = ["red", "blue", "green", "yellow"];
    var started       = false
    var level         = 0;
    
    function nextSequence() {
      pattern     = [];
      userPattern = [];
      while (pattern.length < 4) {
        var randomNumber = Math.floor(Math.random() * 4);
        var randomColour = buttonColours[randomNumber];
        pattern.push(randomColour);
      }
    
      /*Method 1*/
      for (let i = 0; i < pattern.length; i++) {
        setTimeout(function() {
          $("." + pattern[i]).fadeOut(200).fadeIn(200);
        }, 500 * (i + 1));
      }
    
      /*Mehtod 2*/
      // setTimeout($("." + pattern[0]).fadeOut(200).fadeIn(200), 500);
      // setTimeout($("." + pattern[1]).fadeOut(200).fadeIn(200), 1000);
      // setTimeout($("." + pattern[2]).fadeOut(200).fadeIn(200), 1500);
      // setTimeout($("." + pattern[3]).fadeOut(200).fadeIn(200), 2000);
    
    
      $("h1").html("Level" + " " + level);
      level++;
      console.log(pattern)
    }
    
    nextSequence();
    .red {
      background-color: darkred;
    }
    .blue {
      background-color: darkblue;
    }
    .green {
      background-color: darkgreen;
    }
    .yellow {
      background-color: brown;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <div class='red'>red</div>
    <div class='blue'>blue</div>
    <div class='green'>green</div>
    <div class='yellow'>yellow</div>
    Login or Signup to reply.
  3. Your issue is with the scope of i in for(i = 0;...

    It’s a global for a start, which should be avoided

    Making it for(let i = 0; ... will ensure that i is the correct value for the setTimeout delay

    However: I think using array.reduce
    and async/await
    and jQuery.delay
    and jQuery.promise provides much cleaner looking code;

    var pattern       = []
    var userPattern   = [];
    var buttonColours = ["red", "blue", "green", "yellow"];
    var started       = false
    var level         = 0;
    
    function nextSequence() {
      pattern     = [];
      userPattern = [];
      while (pattern.length < 4) {
        var randomNumber = Math.floor(Math.random() * 4);
        var randomColour = buttonColours[randomNumber];
        pattern.push(randomColour);
      }
    
      pattern.reduce(async (p, button) => {
        await p;
        await $(`.${button}`).fadeOut(200).fadeIn(200).delay(100).promise();
      }, Promise.resolve());
      
      $("h1").html("Level" + " " + level);
      level++;
      console.log(pattern)
    }
    
    nextSequence();
    .red {
      background-color: darkred;
    }
    .blue {
      background-color: darkblue;
    }
    .green {
      background-color: darkgreen;
    }
    .yellow {
      background-color: brown;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <h1></h1>
    <div class='red'>red</div>
    <div class='blue'>blue</div>
    <div class='green'>green</div>
    <div class='yellow'>yellow</div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search