Knowing what costs what is something. But we aren't able to just forget about the costly events, so let's now focus on how to minimize the cost of the program. This way, we will be able to fit more things in it before it starts to slow down.
Comparison events optimization
Calling a function instead
Comparison (Static) events, like the 5th event of the example, "Monster : health <= 0", at any given state of the game, will trigger or won't. The triggering won't change from one tick to the other, except if the variables used change. In this simple case, if the life of the monster is superior to 0, the event will be re-evaluated every tick but won't ever trigger until the monster looses life, so the best way to optimize this is by putting this evaluation just after the monster's life change, like this :
With this simple change, the evaluation will only be made once every time a monster looses life, saving a lot of evaluation for nothing.
The problem is that most of the time when you put such an evaluation in the middle of the event sheet, you need it in more than 1 event. In such a case, I would recommend to just make a function used every time you change the checked variable. In the example, that means just using a function for subtracting life to a monster :
To explain the function in 2 words, the two comments (@0 : , @1 : ) are here to describe what parameters the function uses, the first one being the monster.UID for us to select him, and the second one the damage it takes. The function will handle the death of the monster too.
As a function is called with a real trigger, this won't cost anything to the system.
Activating a group
Sometime, the evaluation every tick is useful and can't be replaced. It can then be activated/deactivated depending on the system state.
The best example for this is user inputs for movements. It usually is something like this :
I used the simulate control action to keep it simple, but you surely have more complicate function to call if you do your movements by yourself. Anyway, that isn't the part we are interested in.
If we think as if we were C2, we would first check if the right key is down and do something if needed, then check if the left key is down, ... making it 4 evaluations per tick.
To reduce this amount, we could add a general condition, checking if any key is down and then doing the 4 previous check if needed. This would reduce the check count to 1 per tick if no key is down, and add 1 evaluation if any key is down.
What we are going for though is 0 evaluation per tick when no key is down, 4 evaluations when at least 1 key is. For this, we are going to need groups :
In this example, you can see that we have :
- event 17-20 : input detection (every tick, but only if the group is active)
- event 16 : a group, not activated on start
- event 12 - 13 : activation of the group when any direction key is pressed (triggered event, no evaluation every tick, just when called)
- event 14 -15 : deactivation of the group when no direction key is pressed anymore (triggered event, no evaluation every tick, just when called)
This technique can also be used for lots of other things, like smooth camera tracking for example (lerp calculation every tick then scrolling, the "camera" group can be deactivated once the scroll position has reach the player's, reactivated when any movement is triggered) :
Note the activation of the Camera group at event 13, when the player starts moving, and deactivation only when the player isn't moving anymore and the camera has nearly reach the player's position. The camera tracking has a cost of 2 lerp and 3 comparisons at least, so it's better to deactivate it when it's of no use.
Collision detection, not really needed
With collision detection being a fake trigger evaluated every tick, it could seem a good idea to try to put it in a group and activate/deactivate it on will. For example, you could try to check the bullet collision with monsters only when a bullet and a monster are spawned. As it is though, it would be of no use. The collision detection only checks the bullet-monster couples, so if there is none, it's already done.
If you want to optimize collision detection, try to reduce the count of objects to check. For example, use a "loading area" around your player, larger than the screen of course. Every monster inside the area should have its collisions activated. Respectively, anything outside of the area should have its collisions deactivated.
TLE are in my opinion a crucial thing to optimize, because they are evaluated every tick. What I showed you here was how to reduce drastically false triggers and evaluations from those events.
Out of these techniques, it's more or less easy to rewrite any event into triggers and groups. This isn't a technique to use too soon on a project though, as the code can start to be confusing and less easy to read/write, depending on your habits. On a big scale, in a project with lots of distinct features, this can save you lots of CPU, allowing you for even more features or Fx.