• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Rhythmic programming, controlling objects with a metronome

R

robbumon

Guest
GM Version: GMS 2
Target Platform: All

Summary:
In this tutorial I’m going to show you one way to control objects in GameMaker Studio with rhythm. This is if you would like actions or code to run along with the beats of music. Please note that this is not about measuring the inputs from the user, but about using a metronome controller to synchronize events.

Tutorial:
GameMaker Studio defaults your games to run at 60FPS. This means the code in your Step events will execute 60 times per second.

So if you create an object that plays music, and then synchronize other objects based on frames (steps) per beat, then things should stay in sync. Right? Wrong! If your game is running at 60 frames per second, you’re only measuring within multiples of 60. Only if your music is running at 120 BPM (beats per minute) are things going to stay in sync.


Beats Per Minute (BPM)
Music tempo is generally measured in beats per minute, BPM. This is going to vary per song, and sometimes vary within the song itself! Let’s say your music is a little faster than 120, say 130. Then SIMPLIFIED, it would visually look like this:


So how are we going to overcome this obstacle without varying or changing the FPS of the game? We can use the built in function: delta time.


Delta Time
Delta Time (delta_time) is the time passed in microseconds between each step. Our objects can calculate the microseconds passed, and we can script actions so long as we calculate the BPM of the song to the elapsed milliseconds using delta_time.

Using delta_time, we can tell our object to calculate the time between each of those frames.

If difference from the start of the timer to the point of the calculation matches a beat, then we can run some code or execute some scripts. So let’s get started.


Calculating the Tempo
Let’s assume we know the tempo of the music for our game, 136 BPM, and that it plays at the very start of the file. (0:00:00)
  • 1 minute = 60,000,000 microseconds
  • 1 beat in microseconds = 60000000 /136 BPM (441,176 microseconds)
This is great, but musically 1 beat is just a quarter note. What if we want craziness happening at all sorts of intervals. It’s easy, we can break it down further by multiplying the BPM division against the number of microseconds per minute!
  • 4note_ms = 60000000 / bpm
  • 8note_ms = 60000000 / bpm*2
  • 16note_ms = 60000000 / bpm*3

The Metronome Object
Our metronome object is going to keep the beat! We can have this start measuring at the same time our audio is started from another object.

Code:
//CREATE
//#######################################
play = false;
bpm = 135;
beat_ms = 60000000/(bpm*3);

note_dtime = 0;   //delta time per note
note_count = 0;   //total count of notes
note_prev = 15;   //previous note count

//these will be our musical triggers!
note_1 = false;
note_2 = false;
note_4 = false;
note_8 = false;
note_16 = false;
We’re going to use the Begin Step event to clear each trigger and reset the metronome.
(NOTE: There’s probably a more clever way of triggering the notes, but I’m going to do it with SWITCH anyway and you can't stop me)

Code:
//BEGIN STEP
//#######################################
note_1 = false;
note_2 = false;
note_4 = false;
note_8 = false;
note_16 = false;
if (play) {
     note_count = 0;
     note_dtime = 0;
     note_prev = 15;
     play = !play;
     beat_ms = 60000000/(bpm*3)
     exit;
}
Code:
//STEP
//#######################################
note_dtime += delta_time; //add deltatime passed between steps
note_count = round(note_dtime div beat_ms) mod 16  //count notes

//trigger the 16th notes
if (note_count != note_prev) {
  switch (note_count) {
    case 0:
      note_1 = true
      note_2 = true;
      note_4 = true;
      note_8 = true;
      note_16 = true;
    break;
    case 1:
    case 3:
    case 5:
    case 7:
    case 9:
    case 11:
    case 13:
    case 15:
      note_16 = true;
    break;
    case 2:
    case 6:
    case 10:
    case 14:
      note_8 = true;
      note_16 = true;
    break;
    case 4:
    case 12:
      note_4 = true;
      note_8 = true;
      note_16 = true;
    break;
    case 8:
      note_2 = true;
      note_4 = true;
      note_8 = true;
      note_16 = true;
    break;
    }
  note_prev = note_count;
}
At the beginning of the STEP event we’re adding the delta_time into our variable note_dtime.

The next line is super important. We’re counting every 16 notes in microseconds using the function we used earlier to determine the number of microseconds per note! This is ROUNDED because our game isn’t running at the exact speed of the music. When a new note is incremented, it is the approximate length of time between each beat we measured.

Each note variable will be set to FALSE at the beginning of the step. Then if the note count is incremented, we will set at variable to TRUE.

Other objects in our game can now look at this object and execute code based on when these variables are set to TRUE


And there you have it, a very simple way to keep track of tempo in your game!
 
Top