Chingu FCC Speedrun Challenge: Simon Game
This marks my 9th project in the speedrun challenge, and with this project I’ve essentially completed all the front end projects in the FCC curriculum. I must say, I wasn’t expecting to complete this many projects during the challenge, much less finish the entire first FreeCodeCamp certificate in less than 3 weeks (I’ve actually been studying for over 6 months though). I’m proud to be writing about this project, and I hope I can inspire others on the same path as well. :)
Okay, so let’s talk a bit about the project. First of all, it was really fun to build, it’s the project I’ve had the most fun building, even more than the Pomodoro clock. The biggest reason I’m so excited about this project is that I got to use ES6 generators for the first time! I basically created a class (called Simon
) to handle all the game mechanics and data, and one of its methods is the generator I’m talking about. Instances of the class have an array containing the current pattern in the game, and the way the generator works is it keeps yield
ing the next item in the pattern array until it gets to the end of the array. This is how the generator is defined in code, inside the Simon
class:
*playPattern() {
var current = 0; while (current < this.pattern.length) {
yield this.pattern[current++];
}
}
It’s pretty simple, but to me it was very exciting to use this feature for the first time.
Each item in the pattern is an object with two properties; color
, which is the color of the button in the pattern (a string, either “green,” “red,” “yellow,” or “blue”), and sound
, which is the path to the sound file associated with the button. The objects are picked randomly from an array I’ve already defined (called buttons
) inside the constructor
of the Simon
class, and pushed into the pattern
array. In the main file of my application, I get the generator started by calling playPattern
, and I use the next
method to get the next object in the pattern array. From there, I use the yield
ed object’s properties to figure out which button to light up and which sound file to play. Actually, since I used Howler.js for the sounds, the sound
property is technically a Howl
object, so all I do is call sound.play()
and it plays the sound file defined in the src
property of that Howl
object.
This is how all of this looks in code, defined in a method called play
inside my main app file (which is a Vue file):
play() {
var pattern = this.simon.playPattern(); this.playing = true; var interval = setInterval(() => {
var current = pattern.next(); if (current.done) {
this.playing = false;
clearInterval(interval);
}
else {
let currentBtn = document.querySelector(
`.${current.value.color}`
);
current.value.sound.play();
this.lighten(currentBtn, this.speed / 2);
}
}, this.speed);
}
Of course this is all for when the game itself is playing the current pattern to the user. Things are handled a bit differently for when the user clicks a button. I have a separate method inside the Simon
class for handling these cases:
playSoundByColor(color) {
for (let button of this[buttons]) {
if (color == button.color) {
button.sound.play();
return;
}
}
}
Provided a color string, it looks inside the private buttons
array mentioned earlier (privacy achieved using Symbols) for the button matching the provided color, and it plays the sound associated with the button. The color is passed as a string to the button click handler.
Overall, working on this project has been really fun and rewarding.