GML Restricting Unwanted Repetition with Flags

FrostyCat

Redemption Seeker
Restricting Unwanted Repetition with Flags

GM Version: All
Target Platform: All
Download: N/A
Links: N/A
Summary: A summary of flag patterns for GML development.

Introduction
This guide documents 4 commonly used flag patterns for general GML development. Protecting one-time actions against repetition is an essential mastery for all skill levels and helps avoid many common bugs.

What is a Flag?
A flag is simply a variable indicating the status of something. You can use flags to hold over a status from previous steps, so that currently running code can reference what has happened in the past. One of the most commonly referenced properties of the past is whether an action has already been conducted. By checking and updating this, you can accurately control the recurrence of one-time actions.

Symptoms of Unwanted Repetition
  • Spammed graphical or sound effects (e.g. a trail of effects or repeated sounds like "o-o-o-o-o-ow!").
  • Variables increasing or decreasing by many times more than the amount specified in your code.
  • Variables being disregarded or treated like 1 when counting down.
  • Alarm not counting down despite being set.
  • Staying still or moving in a straight line despite starting a non-linear path.

Pattern 1: Anti-Recurrence Flags
Anti-recurrence flags can be used to perform an action only when a condition transitions from false to true. In GM development, this is most common in collisions, where the condition is a collision-checking function like place_meeting().

General pattern:
Create:
Code:
flag = true;
Step:
Code:
if (condition) {
  if (flag) {
    /* One-time action */
    flag = false;
  }
} else {
  flag = true;
}
A common variation leaves out the else completely, preventing the action from running again on future false-true transitions.
Pattern 2: Was-Is Flags
Sometimes both the false-to-true and true-to-false transitions have associated actions. In these situations, you can use two flags together, one with the current state (is-flag) and another with the previous step's state (was-flag). If the previous and current states don't match, act according to the current state.

General pattern:
Create:
Code:
was_flag = condition;
is_flag = was_flag;
Step: (Recall: ^^ is XOR, which gives true when either operand is true but not both)
Code:
is_flag = condition;
if (was_flag ^^ is_flag) {
  if (is_flag) {
    /* false-to-true action */
  } else {
    /* true-to-false action */
  }
}
End Step:
Code:
was_flag = is_flag;
Pattern 3: Rate-Capping Flags
Rate-capping flags can be used to slow down the recurrence of a repeated action below once per step while a condition is true. This is most commonly used to control rate of fire.

General pattern:
Let INTERVAL be the number of steps between recurrences. To convert a rate to an interval, take its reciprocal (INTERVAL = 1/RATE).

Create:
Code:
flag = INTERVAL;
Step:
Code:
if (condition) {
  if (flag <= 0) {
    /* Repeated action */
    flag += INTERVAL;
  } else {
    flag -= 1;
  }
} else {
  flag = INTERVAL;
}
A common variation is to reset the flag to 0 instead of INTERVAL for a more immediate response.
Pattern 4: Rolling Sum Flags
Rolling sum flags can be used to perform an action every time a numeric value counts past an interval boundary. This is most commonly used to award lives or other rewards at fixed point intervals (e.g. every 10000 points for Pacman).

General Pattern:
Let the numeric value start counting from INITIAL_VALUE and the action recur after every increase of INTERVAL.

Create:
Code:
number = INITIAL_VALUE;
next_trigger_flag = number+INTERVAL;
Step:
Code:
if (number > next_trigger_flag) {
  /* Action */
  next_trigger_flag += INTERVAL;
}
 
Last edited:

Bentley

Member
Oh this is great. I run into this problem all the time. Thanks for the tutorial.
 
Last edited:
Cool. I've done this sort of thing for a while, but this was a very concise explanation and showed some more readable methods of doing this sort of thing.
 
Top