Checking for visibility before collision = bad for CPU, don't try to optimize it?

Not favoritedFavorited Favorited 2 favourites
From the Asset Store
Particles support animations, collisions, effects and etc.
  • I tried to optimize my code a bit by checking if the sprite is visible, and if the layer is visible, before checking for a collision.

    I thought this will cause less collision checks and will cost less CPU. I was half right. It did have way less collision checks but the CPU actually increased a decent amount from the Sprite is visible check alone.

    Using r. 449.2

    This is the test project I used (OneDrive)

    When the Is Visible condition is enabled the CPU is at 5.7% and the checks are at 30.000

    When the condition is disabled

    The checks are 60.000 but the CPU is only 3.9%!

    I'm pretty curious why this happens and if it's normal.

    Any ideas?

  • You’re probably just encountering overhead from the picking system. Picking involves juggling lists of picked object with one known optimization if all the instances are picked.

    So in your case it’s slower to filter 1000 objects down to 500 before looping over it for collision checks, instead of just looping over the 1000 objects to do collision checks. So I’m guessing one case is able to be optimized to be faster over the other?

    In that particular set of events you could try some other things to improve it. One could be to do “sprite overlaps sprite2” instead of “sprite2 overlaps sprite” since you are only dealing with sprite.

    You can also eliminate the else, and the loop for that matter. Loops are known to have a fair amount of overhead.

    Sprite: is visible
    — sprite: set opacity to 33
    — sprite: overlaps sprite2
    — — sprite: set opacity to 100
  • I did some testing, puting the "is visible" after the for each uses less resources than not having the "is visible" or having it before the for each.

    But ROJO's solution uses less cpu and has way less peaks than all the above.

  • Well, this completely shatters my belief system... I always thought filtering the SOL before running a For Each loop was more efficient.

    And it’s not even about collision checks - the same thing happens if you use any other condition inside the loop, like 'Compare instance variable'.

  • Using r. 449.2

    Hi. You are using the optimization condition incorrectly. If you are forced to go through all objects every tick, then at least try to do all the checks in the middle of the iteration cycle.

    To make the result more visible, I increased the number of objects to 10,000.

    If we disregard overhead costs, I think the optimization gives about a 50% improvement.

  • Thank you guys for your feedback!

    skymen also mentioned that putting a check before a collision removes the collision cell optimizations, with BeatsByZann that did some testing on this.

    I also thought, as dop2000 , that filtering before a loop is more efficient because it makes the SOL much smaller and that loops are very resource intensive.

    R0J0hound great ideas, thank you! But why skip the Else though? I always use it because I think an else is always cheaper than doing something on the same tick again, just to be replaced. In your example you set the opacity to 33 each time, and if it's overlapping it gets replaced from 33 to 100 (basically setting the opacity on the same sprite twice in that tick).

    It's less code and it looks cleaner that's for sure.

  • igortyhon thank you for the testing. My point was to first filter all the objects and then do the loop with the check, to make it run better.

    Obviously it didn't work, hence why I asked if people know the reason.

  • also a commonly forgotten feature is the ability to change the collision cell size with a system action (e.g. at start of layout).

    It defaults to the size of the screen, which is usually too big.

    So reducing it to roughly x2 the common object size is probably going to help boost performance as well.

  • igortyhon thank you for the testing. My point was to first filter all the objects and then do the loop with the check, to make it run better.

    Obviously it didn't work, hence why I asked if people know the reason.

    But (visible) is not a trigger, and when you have one object on stage, you can do this, and it will check that object. But when you have 500 objects, which object will be checked for visibility?

    This creates uncertainty, and thanks to Construct3, such code did not generate an error. But it is good practice to choose in the code which object you need to check through the peak or go through all of them.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • I figure that setting opacity is just setting a number so it’s light to set it twice. Else does a bit more than just run if the previous event was false. I tend to only use it in simple cases like you did since how it behaves with more complex picking isn’t entirely intuitive to me. However, it may be mostly a personal preference to do things in as few events as possible.

    I was almost going to write out some pseudocode for all that the events are functionally doing under the hood but I’m not sure that would be useful. I’ve only perused the source for the picking system in the C2 days, but mostly regard it as a black box so I don’t know all that’s going on other than basic behavior.

  • I figure that setting opacity is just setting a number so it’s light to set it twice. Else does a bit more than just run if the previous event was false. I tend to only use it in simple cases like you did since how it behaves with more complex picking isn’t entirely intuitive to me. However, it may be mostly a personal preference to do things in as few events as possible.

    I was almost going to write out some pseudocode for all that the events are functionally doing under the hood but I’m not sure that would be useful. I’ve only perused the source for the picking system in the C2 days, but mostly regard it as a black box so I don’t know all that’s going on other than basic behavior.

    Thanks for explaining :)

  • Here is another fun example - a massive 55% difference in CPU utilization when I replace the condition inside the loop:

    Can anyone explain?

    Project file:

    dropbox.com/scl/fi/l01aj1fqnc916d78gob70/LoopPerformanceTest.c3p

  • system conditions/expressions don't do picking, so they're faster.

  • Yeah, but +55% CPU usage - it makes no sense! And if I move the "is visible" condition inside the loop, the difference is only 3%

  • Yeah, but +55% CPU usage - it makes no sense! And if I move the "is visible" condition inside the loop, the difference is only 3%

    dop2000 I think our colleague Je Fawk found a bug. In fact, with these tasks, a load of 5-10% is normal, because it only involves checking two parameters in a total of 3,000 objects. This is an easy task for JS, and all this load is mainly overhead and rendering costs.

    For such a task, a load of 60% is something abnormal.

Jump to:
Active Users
There are 1 visitors browsing this topic (1 users and 0 guests)