The level editor was implemented in the same project as the game, acting as its own game mode. The user should be able to fully design a level for the game, making use of all the features and mechanics available. Game Levels are stored as JSON files which contain all the necessary information to load the game such as the level name and song, how many band members are there, the time position of every note appearing for any member on any note line, etc. The level editor can automatically save created level in this JSON format, outputting the file. This level file can then be placed into the assets folder so that either the main game can run it, or the level editor can retrieve it for further editing.
The entire level editor revolves around one value: the Song Position. The location of every note, beat, and trigger in the level is determine by its own song position (i.e. at what time in the song a note must be hit). We are loading the song into the game as a .wav or .ogg file which we place into the assets folder. In this file format, the song is played as a byte stream, telling the speakers on the user’s device exactly how to oscillate to produce the desired sound. The fundamental unit for this format is the Sample - a single step in the sound stream. Think of samples in the sound as you would think of frames in a film. The film is a series of still images, or frames, which you step through very quickly to produce fluid motion. Similarly, the music is a series of instantaneous speaker diaphragm locations, or samples, which you step through extremely quickly to produce the correct vibrations for the music. Because audible sound requires extremely rapid vibrations, the sample rate, or frame rate, of the sound file must be extremely high. It is typically 44100 samples per second! What this means is that every second, 44100 samples of sound have been outputted by our speakers, and the audio stream of our sound file has advanced by that many samples. Moreover, at any time in the song, we can simply check the audio stream to see what sample in the song we are in. For example, every time we run update() in the level editor, that is, about 60 times per second, we can poll the audio stream to see what sample in the song we are in. Doing the math (44100/60) we should expect that the sound has advanced about 700 samples since the last time we polled. This sample position, which we call the Song Position in the level editor, is the fundamental time-piece of the game. It is the grand clock that all other game systems look at to know their temporal location in the level. For every note in the level, there is associate a certain song position, or sample, where we want the note to have to be hit. For example, if we want a note that appears and must be hit at exactly 2 seconds into the song, that note has the song position (44100*2) = 88200.
The main editor screen is composed of rectangular screens for each band member in the level. With the usual 4 band members, you will have 4 rectangles, or lanes, at the center of the canvas. These rectangular lanes are divided up into note lines based on the line number for the band members. With the usual 4 note lines, each band member lane is split into 4 note lines. We can now index the horizontal location of a note by specifying what lane and line it belongs to. For drawing the note on the screen, we have a specific helper function (linetoScreenX()) which takes in the lane and line of a note and calculates to correct x-coordinate on the game canvas where the note should be drawn. Similarly, we can abstract the vertical location of the note using its song position. We have another helper function (songPosToScreenY()) which takes in a song position and returns the correct y-coordinate on the game canvas. However, the entire level is not mean to fit in the height of rectangle lanes. Instead we are more zoomed in and centered on a certain location in the level. This location is of course expressed as a song position. Thus, based on how zoomed in the user is, and what song position the user is centered on, we have a helper function (onScreen()) which takes in a song position and returns if a note at that song position would be visible on screen - if it is located within the view of the lane rectangles. Now, using the up and down arrow keys, we simply increase and decreases the song position the user is centered on, and thanks to our helper functions, all the notes will translate accordingly, appearing once we are close enough to them, and disappearing once they reach the edge of the lane rectangle. Similarly, all the calculation for the helper functions above also take into account how zoomed in the user is on their song position. We thus use the left and right arrow keys to change to zoom factor, creating easy zoom-in and zoom-out functionality. Finally, when the user presses the play button (spacebar), we want to start playing the music, with an indicating horizontal bar showing where exactly in the level editor we are at a time in the music. Again this is done with song position. When we start playing the music Audio Stream, every update() loop, we can poll the audio stream, asking for what sample in the song we are in. We then use this as the song position of the song bar, which we draw onto the screen using the helper functions described above. We can also pause, resume, and reset the song. We can even decide to visually track the song progressing through our level by simply setting the song position the user is centered to the song position of the song bar following the music. I hope it is clear by now the importance of song position in orchestrating the location of everything in the level editor.
Competency Flags:
Competency flags, or CompFlags, allow you to change the rate at which a band member’s competency drains, or the amount of a band member’s competency gain rewarded when hitting a note. You can change these at any song position in the level for any band member by placing a CompFlag in the exact same way you place notes in the level. Select CompFlag placement by clicking the yellow star at the bottom left. Before this, make sure to enter the CompFlag settings (yellow button next to star) and set your desired new competency drain rate and note gain. If you want, for example, to change the drain rate but not the note gain, just set the note gain to the same value it was previously. When selecting CompFlags placement, all the notes will be invisible and you will only see CompFlags, when not selecting CompFlags placement, they will be invisible.
(Note: undo/redo doesn’t work for random hits)
Random Hit:
a random hit is an event where a random band member suddenly receives a loss in competency. These can be placed like CompFlags by clicking the red star. Before this, make sure to enter the Random Hits settings (red button next to star) and set your desired probabilities. For each band member, a probability can be set as a percentage (from 0 to 100) which is the likelihood they will be targeted with the hit. As a result, YOU MUST MAKE SURE THE SUM OF ALL MEMBER’S PROBABILITIES IS MAXIMUM 100! If the sum is less than a hundred (say 70), than the remaining probability is that none of the band members are targeted and no hit occurs (so 30% change of no hit occurring). When selecting Random Hits placement, all the notes will be invisible and you will only see Random Hits, when not selecting Random Hits placement, they will be invisible.
(Note: undo/redo doesn’t work for random hits)
Settings: