Fast Loops


Before we can understand how a fast loop works, we must first understand how MMF2 works...

The default frame rate for Multimedia Fusion is 50 frames per second. In each frame, MMF2 completes one loop of your code. Each event is read one at a time from top to bottom and each action within that event is executed one at a time from top to bottom. Once the final event has been executed, the screen is updated or "redrawn" and the entire process is repeated, 50 times per second.

When MMF2 executes a Start loop action, the main event loop is paused right there and then and the fast loop begins. Until that fast loop is over, all events outside that fast loop will be ignored. A fast loop can be run as many times consecutively as you wish (within reason) and be stopped at any time. Let's take a look at the various fast loop actions and expressions.

Start Loop
The Start loop action is created by right clicking Special Conditions in the Event Editor and selecting Fast Loops. First, specify the name of the loop and then how many times you wish it to run. For example...
When the user presses spacebar, the fast loop "Add" will begin. On each loop, 1 is added to the value of the Counter. MMF2 only redraws the screen after all the events and loops have been executed, so to the user, it will appear as if 200 was instantly added to the counter, as opposed to 1 being added 200 individual times.

Stop Loop
Depending on the complexity of the fast loop, MMF2 is capable of running it many thousands of times. Setting a fast loop to run for -1 times will make it run forever. However, running a loop forever will crash your program, so you must stop the loop at some point with a Stop loop action. For example:
Pressing spacebar will start the fast loop. It will continue to loop until the Counter reaches 10000. Once again, it will appear as if the 10000 was instantly added to the Counter.

Comparing to the Loop Index
Alternatively, you can refer to the loop index. The loop index is an invisible counter which increases by 1 every time the loop repeats and resets to 0 once the loop is over. To compare to the loop index you must create a Compare two general values condition. For example:
The time the fast loop will continue to loop until the loop index is equal to 10000, and then it will stop. However, the Counter won't equal 10000, it will equal 10001. This is because all loop indexes begin at 0, not at 1, and the loop index actually equals 10000 after the 10001st loop.

Retrieving the Loop Index
Another extremely useful feature of the loop index is one's ability to retrieve it. For example:
In this case, the Counter will equal 10000, because although the loop index does not equal 10000 until the 10001st loop, we are setting the Counter directly to the loop index itself. Through practice, all of this will soon become second nature.

Setting the Loop Index
Another important (and mostly unknown) fast loop feature is the Set loop index action. First, you specify the name of the loop and then the loop index number you wish to change to. For example:
On every loop, the Enemy will move 1 pixel to the right. The loop runs for 100 times, but at loop 50, it jumps to loop 60. This means although we initially ran the loop 100 times, the Enemy will only move 90 pixels, because 10 loops were skipped. For a more practical application of the Set loop index action, check out the Text Blitting tutorial.

Subsequent Actions
Ever the economists that we are, we will always try to perform our various programming tasks in as few lines of code as possible. One way we can do this is by strategically ordering our events and actions. When a fast loop is over, MMF2 will resume executing actions where it left off. For example:
When the user press Spacebar, the fast loop will begin. The loop runs 100 times and each loop moves the Enemy 1 pixel to the right. After 100 iterations, the fast loop stops and MMF2 resumes executing code where it left off, in this case from the second condition of the first event, Destroy the Enemy.

To the user, it will be as if pressing Spacebar instantly destroyed the Enemy, never knowing that it actually moved 1 pixel 100 individual times before it's inevitable destruction. Obviously, the code above is pointless. For a more practical application, check out the Text Blitting Part 2 tutorial.

Fast Loops and Spread Values
The Spread Value action assigns each instance of an object, a different ID value (stored in the alterable value you specify). These values are assigned sequentially, starting with the most recently created instance, which is set to the value you choose to spread, while older instances are set to progressively higher values.

By comparing this value to the loop index, you can loop through each instance individually. Consider this hypothetical scenario/problem: There are an unknown amount of Enemies, each carrying an unknown amount of gold, how much gold are they carrying in total? This is how we find out:
The first Always event constantly spreads a unique value across all Enemy objects, into an alterable value named ID. It is necessary to always assign this value in the event that an Enemy is destroyed, in which case the loop indexes and ID values would otherwise not match up.

Due to a bug in MMF2, strange things happened if you a spread value in the same event that starts a fast loop. A second Always event is required. This event resets the global value Total Gold to 0 and runs a fast loop which loops through each Enemy, adding it's Gold value to Total Gold. Once the loop is over, a Counter is set to this value.

The loop is run as many times as there are Enemies. Say we have 3 Enemies, the loop is run 3 times, with the loop indexes being 0, 1 and 2, matching the 3 Enemy ID values, which also begin at 0. The first loop isolates the first Enemy and adds it's Gold value to the Total Gold value, the second loop isolates the second Enemy, and so on...

When comparing the loop index to an alterable value, be sure to use Compare to one of the alterable values and not Compare two general values. For an in depth explanation why, read the article, Compare to one of the alterable values VS Compare two general values .

Nested Fast Loops
Also known as recursion, nested fast looping is the simple task of running one set of fast loops inside another. Demonstrated with another hypothetical scenario/problem: There are an unknown amount of Marines and an unknown amount of Aliens. We wish to constantly update each Alien with the distance horizontal to the closest Marine...
The first Always event spreads a unique ID value across all Marine and Alien objects. It also resets the Closest Distance variable to an extremely high value, 99999. You will see why a little later.

The second Always event starts the first loop, Phase 1, once for each Alien, which then starts the second loop, Phase 2, once for each Marine. Now say we have 3 Aliens and 2 Marines, this means there we will be a total of 6 loops. 3 Phase 1 loops, each starting 2 nested Phase 2 loops.

Each Phase 2 loop will compare the distance between the currently isolated Alien (the loop index of Phase 1) and the currently isolated Marine (the loop index of Phase 2). Using the Min() function, we test if that value is lower than the current value stored in Closest Distance and if it is, replace it. Hence the high starting value.


Optimising your Fast Loops
As you can see, fast looping can get pretty complicated and running too many complicated fast loops per frame will reduce your framerate. By nature, fast loops are actually quite slow. One way to speed them up a little is to place each loop's events inside a separate group and only activate that group when you call the fast loop. For example:
This is because every time MMF2 runs a fast loop, it will perform a string comparison on every On Loop condition, checking if it matches the current loop name. This is extremely inefficient. However, MMF2 will not check any On Loop condition hidden inside a deactivated group. This is because MMF2 only parses events in activated groups.


Until next time, my friend.