Whilst the brief certainly did not limit craziness, it was definitely not a requirement. Up until this point, we had covered the basics of the three technologies, and briefly visited some of their friendly companions: SASS (SCSS), Bulma, and the ever-so-friendly jQuery. We had also tried our hand at simple games in class and for homework, including Tic Tac Toe, which is surprisingly complicated to build at this stage. Our games, however, could be anything we wanted so long as they were reasonable, and we were encouraged to tap into our interests.
The natural choice, for me, was a music game of some description. I have played classical music since I was five, and have a deep seated interest in orchestral music (despite not playing an orchestral instrument) — especially that of Romantic and early 20th century composers. I also spent four years studying composition at the Guildhall School of Music & Drama (with six months of that spent at Koninklijk Conservatorium in The Netherlands) so I almost couldn’t not base it on this interest. It does sadden and frustrate me that classical music is seen as “boring” and “uncool” because it could not be further from the truth. So I set out to create a game that was both fun and educational. The Guitar Hero/Rock Band framework is so iconic and well known, so why not build on that!
Resisting the urge to go crazy and have the user play the first bassoon part from Stravinsky’s Prelude to Le Sacre de Printemps, I decided on Tchaikovsky’s Swan Lake op. 20 no. 10 Scène, with the user playing first oboe. The world cup was finishing at the time I was starting the game, and ITV had used it in their titles, so it was extremely well known. Plus it was also easy to code: it stays in the same tempo throughout (albeit one that is not divisible by 60 or 90,) stays in the same metre throughout, and features no complex rhythms that would be a pain to divide.
Quickly, I found myself getting swept up in this idea of a beautifully styled game, featuring a conductor character, a setup feature to allow the user to customise gameplay, and the most beautiful styling this world has ever known. But first, I had to build the game itself.
It wasn’t long before I came across my first problem. My second task (after assigning audio files to keypresses) was to generate divs with the keypress commands inside them, and to have these pop up on the screen in time with a metronome backing track. Not for the first or last time, setInterval() let me down here. It’s amazing how quickly it slips out of time, even on an up-to-date Macbook Pro running Chrome. I could not get half a bar in before it was completely out of time. Thankfully, I quickly found a solution, but it wasn’t a quick one. Each div is controlled on its individual setTimeout(). This way, I can keep the divs beautifully in time, because if one setTimeout() lags, it doesn’t have a knock-on effect. I was able to calculate the number of milliseconds a setTimeout() would need to wait before popping up, based on the time already elapsed, and the note value of the note before. The downside is that each div had its own function. There are over one hundred notes in the piece…
Of course, there is something to be said for refactoring. My JS file, as a whole, is somewhat Herculean. I tried refactoring the setTimeouts but found things went very wrong when I got to rests. Since this was my first go at doing a substantially sized project, I decided it was best to have WET code that worked, than DRY code that didn’t. Obviously.
Next came collision detection — a topic I feel I may write a longer, separate post about, because it sure was a learning curve! Sure, collision detection is not hard in principal. But when you have to get the dimensions of several elements — all but one of which were animated by this point — it is another kettle of fish. What made matters even harder was that my collision zone was bang on in the middle of the page. To have this target area in the centre was a design decision for better UX. Musicians are used to sight reading, and reading a few bars ahead, so this motion made sense. However, it meant it was much harder to get the note that I needed to check for collision! I couldn’t check for the first note on the DOM. I couldn’t even check for the first note with a class of that keypress.
Eventually, I found a rather convoluted work around. First, I gave each div a class of its keypress. Annoyingly, this meant diving back into my hundred plus setTimeout() functions. Next, I give each div a class of dead just after they hit the collision zone. So, I could check for a collision between the stationary collision zone, and the first div that a) has a class equal to the keypress, b) does not have a class of dead, and c) does not have a class of miss, which is applied if the div isn’t within the collision zone.
Finally, after getting collisions working, it was all downhill from there!
After adding in a score function, and something to tell the user how they’ve done, I was at MVP. Time to add extra features! From random squeaks to play when the user hits a wrong note, to bonus scores/booing, to some intro pages complete with an “audition” page to introduce the keypresses to the player.
Finally came styling. Up until the final day of the project, the only styling I had done was some layout for the collisions. Throughout the day, I added some black and white background images, some gradient gold text, and some beautiful Google fonts. Somehow, I even found time to photoshop Emmanuel Macron’s head onto a stock image conductor for the lols.
Was it Even Worth It?!
In short: yes, but eventually…
The longer answer is: yes, and it was a very steep learning curve. It was the first coding project I had built on any significant scale, and was built after a week. Upon finishing the project, I did not want to look at it again for some time. But I have since found a great deal of value in it.