I believe this varies from author to author.
I, in particular, can not even be called a "programmer," I'm more of a curious, enthusiastic. I have technical programming courses, yes, but that was in 1988, specifically in Basic for the computers of the line Apple II Unitron, something that neither is used more presently.
However, the concepts learned in the past are valid for any tool or language. Since we did not have the advanced capabilities of today, the solution I used was mathematics pure and simple. In reality, what these new tools do today is nothing more than exposing the result of mathematical operations on the screen. The "cat leap" is in the user's participation, which no longer has to worry about performing the calculations or breaking the head with formulas. Just click, drag and drop. The rest is result of logic.
In my case, I have not yet been able to learn most of the tools and languages available. I have identified myself (and concentrated) on Basic (for Apple II, but for MSX, my preferred, I am very bad), Flash Actionscript 2 (AS2), Dark Basic and GML (Game Maker Language). Still, I'm no expert on any of them, but I can turn around (okay, every once in a while, I burn the patience of our friend Rozyrg, hehehe).
Faced with this scenario, my option is to use and abuse trigonometry. Combining trigonometric operations with the use of variables (boolean or not), it is possible to create apparatuses that enable to activate / deactivate enemies, to change their firing sequences, to make them vary of movement, to increase / decrease the difficulty, to construct scenarios in a random way (this part is a lot of fun), in fact, with the simple use of mathematics you build a universe, define its laws and execute them.
The use of "triggers" and other types of conditioning factors is paramount for everything to work with satisfaction. It is up to the designer to foresee all the possibilities of something to occur in a different way from the planned one, and thus, to circumvent the problem, making the program resume its "natural" order.
I also use variables based on cycles, which are constantly checked during their execution. If certain conditions are met, the magic happens.
Here is an example in simple GML, which, I believe, can be adapted to any progamming language:
// - - - - - - - - - - - - - - - - - - - -
// In the "create" event
// Defines a variable that allows the enemy to fire, and another variable that controls the interval between shots
shoot = 0
time_shoot = 0
// - - - - - - - - - - - - - - - - - - - -
The next part defines the duration of the firing check cycle. As it is, the cycle has been set to a count and 0 to 10. Reaching the maximum allowed value, the cycle back to begin. You can change the values at will, depending on the duration you want.
// In the event "step"
time_shoot + = 1
if (time_shoot> 10) {
time_shoot = 0
}
// - - - - - - - - - - - - - - - - - - - -
By default, Game Maker has its own function to calculate intervals, called "alarm". In the example above, the user is allowed to get various results without depending on the said function, which has limited use to eleven (though you are unlikely to use more than that).

With the predefined shot cycle code, the conditions for triggering must be established. The code, as it stands so far, only serves to count from 0 to 10, in an infinite cycle, until something happens and forces the machine to take another step.
Is it necessary to use this? Many will say "NO". I like it, because I can create almost unlimited options, depending on the combination of calculated variables.
The previous part of the code tells you to count in a closed cycle, in loop. It's an unconventional variation of the classic "for ... next".
Let's fire now?
// - - - - - - - - - - - - - - - - - - - -
// Still in the "step" event, just after the first part of the code:
if (time_shoot == 5) {
shoot = 1
instance_create (x, y, object_bullet)
}
// - - - - - - - - - - - - - - - - - - - -
The code now defines that when the cycle check variable reaches the value 5, the variable that allows firing changes its value. This value, which was 0, now changes to 1 (the famous boolean). With this satisfied condition, an enemy on the scene will shoot automatically, regardless of what happens around them, as long as it is "alive."
If you add a few lines to the code, repeating the formula and changing the values, you can cause the enemy to perform various actions, within the range of the predefined cycle. This simple scheme allows you to not only make an enemy make an enemy fire a burst of bullets, but also to make him change direction, attack, evade, counterattack, change form, use another type of weapon, anything.
You can also connect these conditioning factors to infinite others, associating the actions of that enemy within a certain period of time, at a certain point of the mission, to a specific place in the scenario, there are no limits to creativity.
See some usage examples:
Environments made with semiprocedural generation

Environments and attack patterns

Using a similar code with little and simple modifications, you can manage all game elements and build a dynamic environment, that almost never repeat itself. See my 1st prototype made in AS2, ten years ago:
https://www.youtube.com/watch?v=VAe4HodY7Zg&t=3sToo many bullets with a simple code (in AS2):
