This is a small blog post about a thing that I've now explained so many times that it became obvious that it needs a blog post.
People are constantly asking about how built-in alarms work and how they could be replicated with custom GML code (for having >12 alarms, organization, or else).
Quality of explanations and equivalent code often varies, so here I explain both.
The logic
The logic behind alarms and alarm events is all pretty simple:
For each alarm, If alarm[i] is greater than 0, Decrease alarm[i] by 1 If alarm[i] is no longer greater than 0, Perform Alarm #i event
As a bonus fact, alarm[] values are integers, rounding to the nearest number on assignment.
The code
Translating the shown logic to code is all pretty simple.
Create Event:
myalarm = 0;
Step Event:
if (myalarm > 0) { myalarm -= 1; if (myalarm <= 0) { // trigger } }
However, believe it or not, the Step event can be written in even shorter form:
Step Event:
if (myalarm && !--myalarm) { // trigger }
I assume that this is a point where a decent amount of readers might have questions, so:
- By GML' rules, a value is considered "true" if it's larger than 0.5. therefore the > 0 comparison can be omitted.
-
--myalarm is standard (C-like) syntax for decrementing a variable before retrieving it's value.
For example, a = --b would be the same as b -= 1; a = b;.
In this case, it allows to omit a nested if-layer that only decreases that variable. - Logic inversion operator follows the same "truthness" rules, therefore !a yields true if (a <= 0.5) and false if (a > 0.5). This allows to omit the second comparison too.
- Finally, by the rules of boolean AND (short-circuit evaluation), the right-side expression is not evaluated if the left-side expression is not "true". This prevents the variable from being decreased into negative infinity after reaching zero.
In other programming languages, this would be best written as
if (myalarm > 0 && --myalarm <= 0) { // trigger }
Since most of them do not evaluate "truthness" of values the same way as GameMaker does (either assuming anything but 0 to be true, or always requiring explicit comparisons).
And that's it. Have fun!.
I’m getting a strange behavior out of that.
(if my_var && my_alarm && !–my_alarm)
versus
(if my_alarm && !–my_alarm && my_var)
Assuming that my_var is always 1, for some reason the only the second line works. Any idea?
If my_var was truly always 1, the two statements would be equivalent.
If it isn’t, then your alarm wouldn’t tick down while my_var is false in the first case due to short-circuit evaluation.
Pingback: GameMaker Tutorial: Delta Time - csanyk.com
I’ve always done:
I’ve been doing something like this for a while now.
I usually use an array to index the alarms I have like this:
a[0] = -1;
And to check if the alarm has sounded I just check to see if a[0] = 0
Very intelligent work around. It took me a few seconds to see how the code worked.
Brilliant.
I generally use a variable called t, t_2, or t_reload, etc for this exact thing. In almost all my objects I have something similar to this. This post has completely changed how I will program moving forward, so thanks :)