Register a series of clicks in JavaScript

3

I am working on an HTML5 game of memory called SIMON in which there is a board with 4 colored pads (green, red, yellow and blue), an ignition switch and 2 buttons to play in different modes.

The user must click on the number of pads that are indicated according to the round and in the correct order, if not, the round must be repeated. I have not finished the JS section yet.

My question is this: I have written a function that illuminates and reproduces the corresponding pad and verifies the click, but only for the first round. I'm confused about how to do it for the next rounds (10 or 15 rounds maximum) where the function runs several times and there must be a delay / wait for the user to click.

I've been in this for a couple of months, but I have not been able to capture it. Should I use recursive functions to define the main function of the game? Store the clicks in an array / object? Do several small functions as modules to call later and simplify the code?

This is my code (also available at CodePen ):

$(document).ready(function() {

  var randColors = [];
  var player = [];
  var normalClicks = [];
  //This variable will be used to check
  //if the game is powered on or off
  var powerCheck = 0;
  // This objects are going to be useful 
  // to identify and shorten many things.
  var greenPad = {
    color: "green",
    gradColor: "green-grad",
    audio: document.getElementById("audio1"),
    item: "greenCanvas"
  },  
      redPad = {
        color: "red",
        gradColor: "red-grad",
        audio: document.getElementById("audio2"),
        item: "redCanvas"
      },
      yellowPad = {
        color: "yellow",
        gradColor: "yellow-grad",
        audio: document.getElementById("audio3"),
        item: "yellowCanvas"
      },
      bluePad = {
        color: "blue",
        gradColor: "blue-grad",
        audio: document.getElementById("audio4"),
        item: "blueCanvas"
      };

  // Illuminate and play a pad's sound  
  function illuminate (col) {

    if (col === "green") {
      console.log("color was green");
      greenPad.audio.play();
      $("#green").addClass("green-grad");
      setTimeout(function() {
        $("#green").removeClass("green-grad");
      }, 500);
    }

    if (col === "blue") {
      console.log("color was blue");
      bluePad.audio.play();
      $("#blue").addClass("blue-grad");
      setTimeout(function() {
        $("#blue").removeClass("blue-grad");
      }, 500);
    }

    if (col === "red") {
      console.log("color was red");
      redPad.audio.play();
      $("#red").addClass("red-grad");
      setTimeout(function() {
        $("#red").removeClass("red-grad");
      }, 500);
    }

    if (col === "yellow") {
      console.log("color was yellow");
      yellowPad.audio.play();
      $("#yellow").addClass("yellow-grad");
      setTimeout(function() {
        $("#yellow").removeClass("yellow-grad");
      }, 500);
    }
  }    


  $( ".onoffswitch-label" ).click( function() {
    powerCheck = powerCheck + 1;
    console.log( "powerCheck = " + powerCheck );

    // If powerCheck is an odd number, it means
    // that the game has been powered on,
    // and now the user can start playing.
    if ( powerCheck % 2 === 0 ) {
      console.log( "Turned Off" );
      randColors = [];

      $( ".count" ).removeClass( "led-on" );
      //Add "disabled" status to normal 
      //mode (Play) and strict mode buttons again.
      $( ".btn" ).addClass( "disabled" );
      //$(".btn").prop( "disabled", true );
      $( "canvas" ).prop( "disabled", true );
      //$("canvas").addClass("disabled");
      //Reset counter to "00"
      $( "#counter" ).text( "00" );
    } else {

      //The game has been turned on
      console.log( "Turned On" );
      randColors = [];

      // Generate random color secuence
      function randomColorsGenerator() {
        while ( randColors.length < 10 ) {
          if ( Math.random() * 4 < 1 ) {
            randColors.push( "red" );
          } else
            if ( Math.random() * 4 >= 1 && Math.random() * 4 < 2 ) {
              randColors.push( "blue" );
            } else
              if ( Math.random() * 4 >= 2 && Math.random() * 4 < 3 ) {
                randColors.push( "yellow" );
              } else {
                randColors.push( "green" );
              }
        }
        console.log( "Actual color sequence is (" + randColors + ")" );
      }

      //Change color of led display numbers
      $( ".count" ).addClass( "led-on" );
      //Remove "disabled" status from normal 
      //mode (Play) and strict mode buttons
      $( ".btn" ).removeClass( "disabled" );
      //document.getElementByClassName(".btn").disabled = false;
      //document.getElementsByName("canvas").disabled = false;


      //POST (Power On Sound Test)
      //This is optional.
      function post() {
        greenPad.audio.play();
        $( "#green" ).addClass( "green-grad" );
        setTimeout(function() {
          $( "#green" ).removeClass( "green-grad" );
          $( "#red" ).addClass( "red-grad" );
          redPad.audio.play();
          setTimeout( function() {
            $( "#red" ).removeClass( "red-grad" );
            $( "#blue" ).addClass( "blue-grad" );
            bluePad.audio.play();
            setTimeout( function() {
              $( "#blue" ).removeClass( "blue-grad" );
              $( "#yellow" ).addClass( "yellow-grad" );
              yellowPad.audio.play();
              setTimeout( function() {
                $( "#yellow" ).removeClass( "yellow-grad" );
              }, 300);
            }, 300);
          }, 300);
        }, 300);
      }
      // Execute the POST function
      post();
      //End of test

      //Press Play to begin
      $( ".btn-success" ).click( function() {

        // But begin only if the game is powered on
        if ( powerCheck % 2 === 0 ) {
          console.log( "The game is powered off" );
          alert( "To start your game you have to first turn it on " );
        } else {

          // If the game is powered on,
          // Normal Mode begins 
          console.log( "Simon has started in Normal Mode" );
          // Reset counter to "00"
          $( "#counter" ).text(0);
          // Generate a new random array of colors
          randomColorsGenerator();
          // Increment display number by 1
          function incrDisplay() {
            var x = $( "#counter" ).text();
            $("#counter").text( Number(x) + 1 );
          }
          incrDisplay();

          // This function defines Normal Mode gameplay 
          function normal() {


            // Temporary commented
            /*
            for ( var i=0; i<randColors.length; i++ ) {
              illuminate( randColors[i] );
              $( "canvas" ).click(function(event) {
                console.log(event.target.id + " was clicked.");
                if ( event.target.id === randColors[i] ) {
                  console.log( "You did great" );
                  incrDisplay();

                } else {
                  console.log( "Ups! Try Again" );
                  // at this point, the display won't increment by 1
                  // 
                }
              });
            }
            */
          }
          normal();

          // Illuminate 1st element
          illuminate(randColors[0]); 
          // Log 1st click
          $( "canvas" ).click( function(event) {
            console.log(event.target.id + " was clicked.")
            // If the click is the expected color
            if (event.target.id === randColors[0]) {
              // Output message
              console.log("You did great");
              // and go to next step
              incrDisplay();
              illuminate(randColors[0]);
              setTimeout (function() {
                illuminate(randColors[1]);
              }, 300)
              // In case of a mistake, repeat last step
            } else {
              console.log("Ups! Try Again");
            }
          });

        }

      });

      //Or Play in Strict Mode
      $(".btn-danger").click(function() {
        console.log("Simon has started in Strict Mode");
      });

    }

  });

});
/*Generic CSS (Aplies to all devices)*/
@import 'https://fonts.googleapis.com/css?family=Alfa+Slab+One|Black+Ops+One';

body {
  /*
  CSS3 Patterns Gallery. (Carbon) 
  by Atle Mo (design), Sébastien Grosjean (code)
  */
  background: linear-gradient(27deg, #151515 5px, transparent 5px) 0 5px, linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0, linear-gradient(27deg, #222 5px, transparent 5px) 0 10px, linear-gradient(207deg, #222 5px, transparent 5px) 10px 5px, linear-gradient(90deg, #1b1b1b 10px, transparent 10px), linear-gradient(#1d1d1d 36%, #1a1a1a 25%, #1a1a1a 50%, transparent 50%, transparent 75%, #242424 75%, #242424);
  background-color: #131313;
  background-size: 20px 20px;
}

.inline {
  display: inline-block;
}

/*Wrapper*/
#frame {
  background-color: #333333;
  height:414px;
  width: 414px;
  margin: -207px 0 0 -207px;
  position: absolute;
  top: 50%;
  left: 50%;
  padding: 5px;
  border-radius: 50%;  
}
/*End*/

#controls {
  width: 250px;
  height: 250px;
  position: absolute;
  margin: -125px 0 0 -125px;
  top: 50%; left:50%;
  border: 4px solid #333333;
  border-radius: 50%;
  background: white;
  text-align: center;
}

/*Simon title inside white circle*/
.brand {
  font-family: 'Alfa Slab One', cursive;
  color: #222;
  font-size: 4rem;
  margin-top: 15%;
  text-align: center;
}
/*End*/

/* Display/Counter */
.display {
  width:  70px;
  position: relative;
  margin: 7px 15px;
  text-align: center;
}
.count {
  height: 60px;
  font-family: 'Black Ops One', monospace;
  color: #DC0D29;
  padding-top: 10px;
  background-color: #32050C;
  position: relative;
  border: 4px solid #222;
  border-radius: 10px;
  margin: 0 auto;
}
.led-off {
  font-size:3rem;
  color: #430710;
  vertical-align: middle;
}
.led-on {
  font-size:3rem;
  color: #ff0000;
  vertical-align: middle;
}
.label {
  color: #222;
  font-family: 'Oswald', Arial, sans;
  font-size: 0.7em;
  margin-top: 5px;
  text-align: center;
}
.full-red {
  background-color: #FC0102;
}
.clickable {
  pointer-events: auto;
  cursor: pointer;
}
.led {
  width: 6px;
  height: 6px;
  background-color: #32050C;
  border-radius: 100%;
  position: absolute;
  left: 0;
  right: 0;
  margin: auto;
  border: 2px solid #222;
  top: -18px;
}
.sw-slot {
  height: 20px;
  width: 40px;
  background-color: #222;
  position: relative;
  top: 5px;
  border-radius: 2px;
  cursor: pointer;
}
/*End*/

/*Giving buttons a rounded shape*/
.btn {
  border-radius: 40%;
}

/* Power On/Off switch*/
/*Inspiration thanks to: proto.io/freebies/onoff/*/
.onoffswitch {
  position: relative;
  width: 70px;
  user-select:none;
  margin: 30px auto;
}
.onoffswitch-checkbox {
  display: none;
}
.onoffswitch-label {
  display: block;
  overflow: hidden;
  cursor: pointer;
  border: 2px solid #999999;
  border-radius: 20px;
}
.onoffswitch-inner {
  display: block;
  width: 200%;
  margin-left: -100%;
  transition: margin 0.3s ease-in 0s;
}
.onoffswitch-inner:before, .onoffswitch-inner:after {
  display: block;
  float: left;
  width: 50%;
  height: 25px;
  padding: 0;
  line-height: 25px;
  font-size: 12px;
  color: white;
  font-family: Trebuchet, Arial, sans-serif;
  font-weight: bold;
  box-sizing: border-box;
}
.onoffswitch-inner:before {
  content: "ON";
  padding-left: 15px;
  background-color: #34A7C1;
  color: #FFFFFF;
  text-align: left;
}
.onoffswitch-inner:after {
  content: "OFF";
  padding-right: 10px;
  background-color: #EEEEEE;
  color: #999999;
  text-align: right;
}
.onoffswitch-switch {
  display: block;
  width: 30px;
  margin: -2.5px;
  background: #FFFFFF;
  position: absolute;
  top: 0;
  bottom: 0;
  right: 41px;
  border: 2px solid #999999;
  border-radius: 20px;
  transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
  margin-left: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
  right: 0px;
}
/*End of Power On/Off Switch*/

/*Canvas color and shape*/
canvas {
  width: 200px;
  height:200px;
}
#green {
  background-color: #27ae60;
  border-top-left-radius: 100%
}
.green-grad {
  background: radial-gradient(circle, white, #27ae60);
  border-top-left-radius: 100%
}
#red {
  background-color: #e74c3c;
  border-top-right-radius: 100%;
}
.red-grad {
  background: radial-gradient(circle, white, #e74c3c);
  border-top-right-radius: 100%;
}
#yellow {
  background-color: #f1c40f;
  border-bottom-left-radius: 100%;
}
.yellow-grad {
  background: radial-gradient(circle, white, #f1c40f);
  border-bottom-left-radius: 100%;
}
#blue {
  background-color: #3498db;
  border-bottom-right-radius: 100%;
}
.blue-grad {
  background: radial-gradient(circle, white, #3498db);
  border-bottom-right-radius: 100%;
}
/* End */
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>

<div id="frame">
  <div id="4canvas">

    <div id="controls">
      <h1 class="brand">Simon<sup>®</sup></h1>

      <div>
        <!-- Start Button (Bootstrap) -->
        <button type="submit" class="btn btn-success btn-lg disabled" data-toggle="button" aria-pressed="false" autocomplete="off">
          <span class="glyphicon glyphicon-play"></span>
        </button>
        <!-- End -->

        <!-- LCD Display -->
        <div class="display inline">
          <h1 id="counter" class="count led-off">00</h1>
        </div>
        <!-- End -->

        <!-- Strict Mode Button (Bootstrap) -->
        <button type="submit" class="btn btn-danger btn-lg disabled" data-toggle="button" aria-pressed="false" autocomplete="off">
          <span class="glyphicon glyphicon-flash"></span>
        </button>
        <!--End of Strict Mode Button-->
      </div>

      <!-- Rounded On/Off switch -->
      <div class="onoffswitch" id="onoff">
        <input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="myonoffswitch">
        <label class="onoffswitch-label" for="myonoffswitch">
          <span class="onoffswitch-inner"></span>
          <span class="onoffswitch-switch"></span>
        </label>
      </div>
    </div>

    <div>
      <canvas id="green">
        <audio id="audio1" src="https://s3.amazonaws.com/freecodecamp/simonSound1.mp3"></audio>
      </canvas>
      <canvas id="red">
        <audio id="audio2" src="https://s3.amazonaws.com/freecodecamp/simonSound2.mp3"></audio>
      </canvas>
    </div>
    <div>
      <canvas id="yellow">
        <audio id="audio3" src="https://s3.amazonaws.com/freecodecamp/simonSound3.mp3"></audio>
      </canvas>
      <canvas id="blue">
        <audio id="audio4" src="https://s3.amazonaws.com/freecodecamp/simonSound4.mp3"></audio>
      </canvas>
    </div>
  </div>

</div>
    
asked by Jose Barakat 22.10.2016 в 05:45
source

1 answer

3

I have removed code from your example to make it easier, the code that I pass to you is not 100% functional, it is simply to show how you can use the logic of the game.

CodePen

As you will see, there is no need for recursion or anything like that, we only need 2 key variables, which are:

Ronda that tells us two things, the first in which level we are and so we determine how many colors are going to be shown and the second one to know how many colors the player must press to pass the level.

clickRonda serves to control how many colors the player has pressed.

var clickRonda = 0;
$( "canvas" ).click( function(event) {

       illuminate(event.target.id); 

       if(randColors[clickRonda] == event.target.id) {
           //Si entra aqui, singinfica que se ha pulsado el color correcto
           clickRonda++;

           if(ronda == clickRonda) {
               //El jugador a terminado la ronda, aumentamos el nivel!
               ronda++;
               clickRonda=0;
               reporducirNivel(ronda);
           }

       } else {

           //Generamos un sonido diferente para indicar que hemos perdido.
           greenPad.audio.play();
           redPad.audio.play();
           yellowPad.audio.play();
           bluePad.audio.play();

            //Generamos un nuevo array de colores. 
           randomColorsGenerator();
           ronda=1;
           clickRonda=0;
           $( "#counter" ).text(0);
       }



});
var indice = 0;
function reporducirNivel(ronda) {
    $( "#counter" ).text(ronda);

    var tiempo = 600;
    for(var i = 0; i<ronda; i++){
        setTimeout(illuminate, (i+1)*tiempo, randColors[i]);
    }
}

Suppose that your randColors color array contains:

  

0, 1, 2, 3 ... 10

     

(network, blue, green, red, blue, green, green, green, red, green)

Now let's say that we have just started Round 2, that is, ronda=2 and clickRonda=0 and the colors red and blue have already been reproduced.

>

When we click on the red button we will call $( "canvas" ).click the button pressed by the user illuminate(event.target.id); will light up and we will check if the correct button if(randColors[clickRonda] == event.target.id) has been pressed if it is true, we increase clickRonda=1 and check if we have finished the round if(ronda == clickRonda) in our example, it is not like that.

Now we click on the blue color the previous checks are repeated with clickRonda=1 the difference in this case is that the following condition is true: if(ronda == clickRonda) we increase the round and restart the counter of roundRound.

I hope you understand, a greeting.

    
answered by 23.10.2016 / 16:40
source