Let's look at a few things, but first let's dig into the manual:
... But what is an alarm? Well, it is a special event that does nothing unless the alarm has been previously set, and then it will wait until that alarm has counted down to 0 before running the actions or code that you have added into it. Once the alarm has reached 0 and run the code, it will then count down to -1, where it will remain until set again (meaning you can check the value of an alarm to see if it is greater than -1, which will tell you if it's running or not). So, say you set alarm[0] in the create event of the object to 30, this means that GameMaker Studio 2 will count down 30 game steps before it runs the actions or code that are placed in the alarm[0] event. Note that setting an alarm to 0 will not run the alarm code, as the event is triggered, but the alarm set to -1 immediately, so the code is skipped. If you need an alarm to run the very next step, then you should set it to 1.
If we treat this description like a word problem, we can represent alarm with the following code:
Code:
if ( alarm > -1 ) {
alarm = alarm - 1;
if alarm == 0 { // do code }
}
As you can see, alarms are not particularly complicated. They simply count down each step until they reach zero, and then fire the event. Rather than 'steps', it might be easier to think about the game in terms of 'frames'. Dynamic frame rate is more complicated, so let's start simple. An instance will run all of its code during a single frame, that includes the step and draw events. If the game runs at 60 frames per second, it will do this 60 times every second. This means 1 second is equal to 60 frames, and in order to wait 1 second we would need to set our alarm to 60 since it would take 60 frames to reach 0. Then we just extrapolate from there: 10 seconds would be 60 frames * 10 seconds, or 600 frames.
However, there is a pretty big problem here: that is
only true when and if the frame rate is 60. This is what we call a 'magic number', and it refers to a hard coded number that can break the game. Something like the number of frames in a second is a general piece of knowledge, and it could change, but it also should be consistent everywhere. So ideally we want to save that piece of information and use it everywhere, that way we only have to change one variable and everything will match. Take the following example:
Code:
#macro one_second 60
game_set_speed( one_second, gamespeed_fps );
Now if I ever change how many frames per second the game is, one_second will change to match and my alarms would still work properly:
Code:
alarm[ 0 ] = 10 * one_second;
But wait a minute, isn't that 10
also a magic number? Perhaps. While it does represent a number that would affect the outcome if changed, this 10 is specific to the spawner. Changing this shouldn't affect anything but the spawner. However, it will affect
every spawner, and therefore is a missed opportunity to add a little extra control over our spawning. We could make a different spawner for every time: a 10 second spawner, a 5 second spawner, a 1 second spawner, but that would be a lot of code duplication and would make a lot of maintenance if we ever wanted to change the spawner in other ways. In this case we can add some abstraction by also defining how many seconds the spawner should take:
Code:
// create
spawnSeconds = 10;
// step
alarm[ 0 ] = spawnSeconds * one_second;
Now every spawner can actually have a different spawn rate, and we could even adjust that rate while the game is running if we so chose. With a few layers of abstraction in our spawner, we've made it not only easier to maintain, but also increased it's flexibility. These are concepts you'll come to better grasp in time, but for now hopefully this helps, have fun and keep coding!