I've picked up a lot of tricks with the KNP, CNC, TGF, MMF1, MMF1.5, MMF2 architectures. I've been around a while and used them all. And since the dawn of time, klik has been slow. Klik has been inefficient. Built something complex in it, and it will run properly, but do so at 10 FPS, and you'll cry yourself to sleep. Well this is why, and this is what you can do to fix it:


#1: Slow Loops
Short Summary: Put all your fast loop code into event groups, and sandwich your Start Loop event with a Open Group & Close Group event on both sides. This alone can make big games run 30x as fast. Probably at least 10x as fast, depending on what is slowing you down.


Fast loops in Klik are slow by nature. They should be called Slow Loops. This applies not just to the built in fast loops, but the fast loop object, fast functions, etc. Using lots of fast loops in a project, and the game will burn and run like a crippled toddler on a unicycle, yet not as saddenenly funny. This is a trick I picked up from Nifflas, which solves the issue. When a fast loop is called, MMF takes ALL events with an On Loop modifier, and essentially copys/pastes them that many times, runs them all, than returns to the event where it left off. The thing you might not have noticed is, it uses ALL on loop code. If you run a loop that only has a single line of events, it will take ALL the loops in your program and process them. So instead of just reading the lines it needs to, it reads all the lines again, and does string comparisons on the loop trigger. This is incredibly inefficient. If you have a complicated application, with 20+ different fast loops in it, than imagine that every time one of those loops is called, it has to process every other loop. In terms of big O notation, instead of the obvious O(N ), where N is the time-complexity of running your fast loop on average, you have a time complexity of O(N^2). So with one loop, thats O(1) vs O(1), whereas with 20 loops, thats O(20) vs O(400). Thats a huge discrepancy.

The key to solving this issue is that On Loop commands are only parsed from the active event list. When events are located inside deactivated event groups, they are not parsed when the compiler runs through the code. So if you make sure that only a single event group's worth of functions is open at a time, you make it so the compiler doesn't have to read all the OTHER loops. Thus, wherever we previously had On Loop commands, we put all of that same loop into a single group, and wherever we had an Start Loop command, we sandwich it between a Open Group & Close Group event on both sides. While nested loops will still read outer nested loops, the vast majority of the code won't have to be called without use. Don't try fixing the nested loop issue unless its vitally important, because that could be retardedly complicated (you'd have to deactivate an outer loop's group inside the inner loop, and reactivate it when that loop terminates, and your brain will asplode from complicatedness).

So instead of this:

(CONDITIONS)

Start Loop: Hello World for 100 loops


do this:

(CONDITIONS)

Open Group: Hello World
Start Loop: Hello World for 100 loops
Close Group: Hello World


Please note that this will only optimize your code. Programs that ran slowly because they were complicated via fast loops will almost certainly not lag after you apply this (see the difference between my Text based FPS & my MMF2 FPS engine, how much more quickly it runs), whereas programs that ran slowly due to other factors (loading files at runtime, drawing overlay graphics, too many active objects) will see absolutely no difference.



2: Recursion
Short Summary: MMF can do recursion, but you'll never need it.

MMF is capable of recursion. Those of you that know what it is, I don't need to explain it to, and those who don't, I won't. The way in which you can trigger recursion inside of MMF though, is a little tricky. As I mentioned above previously, when you call a fast loop, the compiler picks up in the middle of reading through the actions, does the loop, than returns and finishes reading the actions. For example, if you have this code:

*Upon Pressing Spacebar:

=Start Loop: Stupid for 1 loop(s).

*On Loop: Stupid
+Counter < 5
=Add 1 to Counter
=Start Loop Stupid for 1 loop(s)
=Sub 1 from Counter



When you hit the space bar, the actions will execute in this order:

Add 1 to Counter

Add 1 to Counter
Add 1 to Counter
Add 1 to Counter
Add 1 to Counter
Sub 1 from Counter
Sub 1 from Counter
Sub 1 from Counter
Sub 1 from Counter
Sub 1 from Counter


So instead of alternating adding & subtracting, the code will first execute 5 copies of the first half of the loop, than 5 copies of the second half of the loop. This is important with recursion, because it means you can resolve loops after they execute up until your breakpoint. For example, my pathfinding engine uses recursion to take a single loop and execute a node search with 100% results.

Now, one problem is that you need to look out for INFINITE recursion. Runaway loops in any program = a crash. Try this simple line of code in MMF:

*Upon Pressing Spacebar:

=Start Loop: REALLY Stupid for 1 loop(s).

*On Loop: REALLY Stupid
=Start Loop REALLY Stupid for 1 loop(s)


What happens? The compiler keeps adding the same loop onto the stack, over and over again, and finally your program explodes. To be specific, MMF2 can handle precisely 8351 levels of recursion before it crashes. Attempting to run a 8352nd loop will instantly crash your game. That is to say, if MMF2 has 8352 different loop index's in use, the project runs out of memory for loops and dies. Instantaneous crash, no popups. So um, 8000 loops is a lot, just keep it under that and I seriously doubt anyone will ever need that many layers of recursion.

3: Running old projects (TGF, KNP, CNC)
Short Summary: Activate windows 95 compatibility mode.

When you run TGF or older games on a new computer, they will inexplicably crash. Look at Gridquest; the game has no errors in the code that will cause crashing or memory leaks, but the game will shut down too much for comfort. The reason is because TGF was made with old windows architectures, and sucks on XP/Vista. If you right click on the .exe file, go to properties, compatibility, Run this program in '95 mode. It will reduce crashing by up to 90%. You'll get occasional crashes, but they will be much rarer. The problem is, this mode is specific to each computer. When a player installs your game, he needs to be told to activate this mode. Doing it to the .exe, and putting it on someone else's computer, it will no longer be active. So add a note to the splash screen, or a readme, telling them to carry this out.

4: Apply complex actions to ALL the copies of an active object.
Short Summary: Iterate through your objects in a fast loop, using flags and picking one at random from these, to choose each copy of your object a single time each frame and apply the action to it.

We've all been there. You. The fat kid. You're stuck right now, because you don't understand how to get your Gravity or Platform Engine to apply to all your objects. You have the events in place, it looks like it should work, but when you run it, only a single copy of the object runs the action, the others just sit there and look stupid.

Heres how it works. You need to apply some function to say 100 copies of an active object. But this function is not simple. Maybe you need to check for backdrop collisions with some sensors. Maybe, you just need to pin a sword object into the bad guys hand. Lets use that as our example.


You have the following code. At the start of your game, you create 100 bad guys. You also create 100 swords. You do a Spread value 1 to Value A through both objects. Now, you have 100 bad guys & 100 swords, each numbered 1 to 100. You want to pin the sword on the respective bad guys with the same Value A, so you put in this line of code:

*Alterable Value A of Sword = Alterable Value A of Bad Guy

=Set Position of Sword (0,0) to Position of Bad Guy


But what happens when you run this? All 100 swords pin themselves to a single bad guy. Aren't you frustrated? In fact, it will be the one with Value A = 100; it only chooses the last copy of each object. This is because the condition checking for a sword, and positioning it, can only apply to a single object a time. When the compiler narrows its scope, you still have 100 swords & 100 bad guys in the list. So it applies the Position Object even to all 100 swords, and it chooses only a single Bad Guy as the target.

The key to solving this, is to iterate through the objects. We need to create a fast loop that will run this same command, but apply it once to each set of objects. We do it like this:

*Always:

=Bad Guy: Set Flag 0 Off
=Bad Guy: Set Flag 1 Off

*Always:
=Start Loop Pin Swords for (Number of Bad Guys) loops

*On Loop: Pin Swords
+Bad Guy's Flag 0 is Off?
+Pick a Bad Guy at random
=Bad Guy: Set Flag 0 On
=Bad Guy: Set Flag 1 On

*On Loop: Pin Swords
+Bad Guy Flag 1 is On
+Alterable Value A of Sword = Alterable Value A of Bad Guy
=Set Position of Sword (0,0) to Position of Bad Guy

*On Loop: Pin Swords
=Bad Guy: Set Flag 1 Off


Lets look at this step by step. What does each action do? The first event, the Always, resets the flags of all the bad guys. Flag 1 should never be on, so that event is just redundant, but good practice. Then, after flags are reset, we start the loop 100 times. We look at the list of every single Bad Guy in the game. From the ones we haven't chosen yet, we pick one, and set the matching sword to his location, then unpick him (but via flag 0, we keep track of the fact we already picked him). Then we repeat it, until every single object has been picked. No object will be picked twice, and all objects will be picked. The code won't falter on you.

For general purposes, this iterative construct can be used from this shell:

*Always:

=[Active Object]: Set Flag 0 Off
=[Active Object]: Set Flag 1 Off

*Always:
=Start Loop [Loop Name] for (Number of [Active Object]) loops

*On Loop: [Loop Name]
+[Active Object]'s Flag 0 is Off?
+Pick a [Active Object] at random
=[Active Object]: Set Flag 0 On
=[Active Object]y: Set Flag 1 On

*On Loop: [Loop Name]
+[Active Object] Flag 1 is On
(conditions go here)
(events go here)

*On Loop: [Loop Name]
=[Active Object]: Set Flag 1 Off


5: COMMENT YOUR MOTHER!@#$ING CODE
Really guys. Rename your object variables, put your code in groups, and leave comments explaining what does what. When you come back in a year to look at your game, you'll remember how it works. MMF has extreme case of spaghetti coding. The lack of obvious functions leaves you jumping around like donkey turds. Just use some basic organization skills, it will save you time in the long run.