Making Music Games (a programmer's postmortem)
March 20th, 2012Being a rhythm game, Music Island presented a number of unique and fun challeges from a programming perspective. The great difficulty in programming rhythm-based games is in keeping gameplay synchronized with the game's music. A fully-featured triple-A engine like BASS might be able to analyze the music in real-time and use it to guide gameplay. However, for our one-programmer team, analyzing the stream in real-time was not really an option. We would have to find some way to overlay music onto the game and force the game to keep pace with it.
The concept was fairly simple. We would use MP3 music. With the length of the song, the number of measures, and the time signature, I can calculate the time in milliseconds between each beat - or any subdivision of the beat. When the song is running, the program keeps track of which beat it is on simply by counting up with a Stopwatch. When the time exceeds the amount of time per beat, we go to the next one (carrying over the leftover time).
To have the game actually use this information, I determine what kind of beat the song was currently on (quarters, eighths, thirty-seconds, etc) and the distance in thirty-second notes from the nearest quarter note. If that value is within a threshold, I accept input and generate a spell.
I found that MP3 files were not actually a sufficient solution, for our resources at least (the XNA engine). Despite our best efforts to get accurate timings, I could not make the game stay in sync with the music. Within 5 or 10 seconds, they would be on off-beats, and XNA offered me no way to control how the MP3 was being played to attempt to correct this. I concluded that XNA's MediaPlayer class, which was playing the MP3s, was probably the issue, so our solution was to split the songs up into segments of WAVs. In addition, our songs were designed and composed such that they could be split up into layers by instrument. So we ended up with a bunch of two-measure wave files of single-instrument lines. I wrote an XML format so our composer could stack and sequence these segments however he liked. This helped cut down on the otherwise-huge filesize wav files would have caused by re-using tunes multiple times in a song.
Now with these segmented WAVs, we had far more control over the speed the music was played at, and we were able to synchronize the music periodically. This was ultimately sufficient to keep the game as a whole completely in sync. It was a feature we were still tweaking, though, even after the game's first submission!