I’d like to update the discussion I started on loops and focus on loops that could run every frame. Why those? Because if you link your code with frame rate then you get the best response as well as the smoothest display. What I mean is if you have to move something on the screen, updating it every frame is all you need since this is what you see. No point updating it in between the frames even if you can. Same with response, you can only see the response when you see the frame.

Here are some facts for you. A normal for loop can iterate around 170000 times a second when called directly from event handler or FSM. If you spawn or execVM the same loop you get about 25000 iterations per second. To keep up with the frame rate you only need about 60 iterations per second max.

I have already touched on onEachFrame loop in the previous tutorial. While it is good for a quick and dirty job, you cannot have several onEachFrame loops running next to each other, there can only ever be one. Also it won’t tolerate any script suspension in a form of sleep.

Another way of organising an each frame loop is by setting up an event handler. In ArmA 3 you can use mission event handler “Draw3D”. addMissionEventHandler ["Draw3D", {}] command will call its code every frame. You can also create more than one loop this way to run next to each other. As name suggests this kind of loop should probably be used for HUD updates more than anything else. And since it is event handler it will also not tolerate script suspension. The example of usage is shown here.

Moving on to FSM. Conditions which are linked to the current state in FSM are checked every frame. You also have a precondition section where if you place your code, it will always execute before the actual condition is checked. This code will therefore execute every frame. If you need more than one loop you can create more conditions and link them to the same state. The good thing about FSM is that it gets quite a bit of priority among other scripts. It also doesn’t like script suspension.

fsm

And finally a very unexpected loop construct, made of… waitUntil. By default this command will execute its code every frame until the code returns true. You can spawn multiple waitUntil loops as well if you need to. In order to exit this loop you need to make the very last statement in the waitUntil code to return true.

_null = [] spawn { _time = diag_tickTime + 1; _i = 0; waitUntil { _i = _i + 1; diag_tickTime >= _time }; hint format [ "Code executed %1 times per second", _i ]; }; //Code executed 50 times per second

If this is not enough you can add script suspension to this construct in case you wish to slow the loop even more while still keeping its speed relative to the frame rate. Though I have discovered an interesting anomaly while doing this. Sleep value >0.0005 will make waitUntil to miss a frame every time, which is kind of strange considering how insignificant this delay is.

_null = [] spawn { _time = diag_tickTime + 1; _i = 0; waitUntil { sleep 0.00051; _i = _i + 1; diag_tickTime >= _time }; hint format [ "Code executed %1 times per second", _i ]; }; //Code executed 25 times per second

I guess this has something to do with internal scheduling of the engine, which also brings me to a conclusion that using waitUntil loop in general should require less CPU power than a while loop with sleep delay. Because waitUntil condition is checked per frame so when it is checked it will not be queued for checking until the next frame. while condition on the other hand is allowed to be checked multiple times per frame.

Enjoy,
KK