Handle lots of units

Discussion and feedback on Construct 2

Post » Tue Sep 26, 2017 2:12 pm

Hello everyone,

It's been a while I didn't post in the forums cause I find Construct 2 very complete and I'm used to workarounds. But I'm struggling with one thing, handling many units with behaviors and states updated every tick. (Native application, not mobile)

Basically it's the For Each loop on a family with some calculations and checks inside that are CPU intensive and tend to kill performance.
I've read all Ashley posts about optimization and how to rightly use Construct 2 but in some game design you can't pass the For Each loop.

I encounter difficulties to supress the stuttering when it comes to deal with 40-50 units ingame. With 100 the game is playable but regular small stutters are annoying and low end machines can't sustain. I saw the benefits of collision check optimization that have been done but how could loops can be so demanding ? I tried various things to understand and ran into the case of function calls vs inline events but stress tests were not so relevant.

Anyone has a solution or an idea to organise the code or something to handle (not so) large number of units ? I mean, 200 with no stutter would be cool !

Thanks
B
16
S
5
Posts: 128
Reputation: 1,469

Post » Wed Sep 27, 2017 9:45 am

@Nabu0001

I was thinking about this same issue the other day; this might be a solution:

https://www.dropbox.com/s/35vfsi9j0j8gw ... t.c3p?dl=0

Each tick, the modulo (%) 10 of each sprite.IID is checked against the modulo 10 of the current tickcount and those with the same value are picked ((e.g. if the tickcount is 29, pick all the sprites with an IID that ends in 9).

This means that each tick only 10% of the sprites are selected. You can pick less sprites per tick by increasing the value after the % sign.

In the demo I've set it up so that the sprite's frame changes when picked - if you run the demo you can see the horizontal white band indicating the sprites that are picked.

Now, I haven't stress-tested this to see how it fares when you have a lot of code affecting the picked sprites, but I'm guessing it should at least reduce some of the stutter.
Last edited by mekonbekon on Wed Sep 27, 2017 10:59 am, edited 1 time in total.
B
23
S
9
G
4
Posts: 510
Reputation: 4,437

Post » Wed Sep 27, 2017 10:34 am

Sorry, that was a C3 demo; here's a C2 one:

https://www.dropbox.com/s/1igxvu9v9d2kn ... .capx?dl=0
B
23
S
9
G
4
Posts: 510
Reputation: 4,437

Post » Wed Sep 27, 2017 2:07 pm

I don't know if this work for you, but I sometimes use dictionary to store picked UID's. That way the for each loops doesn't have to loop through a whole family, but only the ones stored in the dictionary. That might work when you have many units in the same family, but let's say 20 out of 100 selected, as you don't have to loop through the 80 that are not selected. I found it to have some performance benefit in some cases.

For me the picking itself seems to use a lot of cpu in some cases, so i try to find ways to use some more lightweight way of picking objects. Restructuring the condition order can help a lot too.

For example:
For each unit (loops through all units)
is Selected. (then picks and filters the ones selected)

insead use.
Is selected (pick the selected ones)
For each unit. (loops through only the selected ones)

Small things like that can help a lot, but you probably know that already. Trying to filter down with conditions as much as possible before running any for each loops and actions, seems to work pretty well in most cases.
Follow my progress on Twitter
or in this thread Archer Devlog
B
44
S
20
G
19
Posts: 1,092
Reputation: 14,378

Post » Thu Sep 28, 2017 6:54 am

I have the same problem and still looking for a solution I hope someone can give us a good hint, I got 16 objects checking distances between them so when is in a empty project with just that 16 objects works ok and when I put the same code on my main project where they are like 150 instances of the same object the CPU goes double and triple doesn't matter how much I filter it with boleans and conditions and all kind of tricks is not working and this is just to check distance between 16 instances on the screen
B
48
S
30
G
92
Posts: 363
Reputation: 51,384

Post » Thu Sep 28, 2017 7:02 am

tunepunk wrote:I don't know if this work for you, but I sometimes use dictionary to store picked UID's. That way the for each loops doesn't have to loop through a whole family, but only the ones stored in the dictionary. That might work when you have many units in the same family, but let's say 20 out of 100 selected, as you don't have to loop through the 80 that are not selected. I found it to have some performance benefit in some cases.

For me the picking itself seems to use a lot of cpu in some cases, so i try to find ways to use some more lightweight way of picking objects. Restructuring the condition order can help a lot too.

For example:
For each unit (loops through all units)
is Selected. (then picks and filters the ones selected)

insead use.
Is selected (pick the selected ones)
For each unit. (loops through only the selected ones)

Small things like that can help a lot, but you probably know that already. Trying to filter down with conditions as much as possible before running any for each loops and actions, seems to work pretty well in most cases.



Hi @tunepunk I show you did an interesting test on this how-do-i-pick-multiple-by-uid-string_t190930 very good test Thanks

Did you manage to find any good results or ways how to improve ?? I will be very interested in that

do you know if is possible example you have 20 objects on the screen the idea is to take the UID of all those 20 objects and just loop between them checking distances between them and depends the distances do some actions those objects, is it possible without looping through the whole 150 instances that are not on the screen
B
48
S
30
G
92
Posts: 363
Reputation: 51,384

Post » Thu Sep 28, 2017 9:17 am

tarek2 wrote:
tunepunk wrote:I don't know if this work for you, but I sometimes use dictionary to store picked UID's. That way the for each loops doesn't have to loop through a whole family, but only the ones stored in the dictionary. That might work when you have many units in the same family, but let's say 20 out of 100 selected, as you don't have to loop through the 80 that are not selected. I found it to have some performance benefit in some cases.

For me the picking itself seems to use a lot of cpu in some cases, so i try to find ways to use some more lightweight way of picking objects. Restructuring the condition order can help a lot too.

For example:
For each unit (loops through all units)
is Selected. (then picks and filters the ones selected)

insead use.
Is selected (pick the selected ones)
For each unit. (loops through only the selected ones)

Small things like that can help a lot, but you probably know that already. Trying to filter down with conditions as much as possible before running any for each loops and actions, seems to work pretty well in most cases.



Hi @tunepunk I show you did an interesting test on this how-do-i-pick-multiple-by-uid-string_t190930 very good test Thanks

Did you manage to find any good results or ways how to improve ?? I will be very interested in that

do you know if is possible example you have 20 objects on the screen the idea is to take the UID of all those 20 objects and just loop between them checking distances between them and depends the distances do some actions those objects, is it possible without looping through the whole 150 instances that are not on the screen


In some cases i found that using LOS behaviour could be a bit better, it's pretty much a range check as well, if you set a 360 cone, and they can also utilize the "use collision cells" option.

Another way that is way less CPU intensive is to use pick nearest/furthest, if something is within the range you set a boolean, and loop through that a few times per tick. It updates slowly but uses less cpu, so can be good for something that doesn't need to be instantly updated, or if you have a lot of instances but most of them are outside the viewport, in other areas of the layout.

Code looks like this:
Image

Edit: Added link to C3 project.
https://www.dropbox.com/s/96e7y0njoqyqd ... e.c3p?dl=0
Follow my progress on Twitter
or in this thread Archer Devlog
B
44
S
20
G
19
Posts: 1,092
Reputation: 14,378

Post » Thu Sep 28, 2017 9:52 am

tarek2 wrote:do you know if is possible example you have 20 objects on the screen the idea is to take the UID of all those 20 objects and just loop between them checking distances between them and depends the distances do some actions those objects, is it possible without looping through the whole 150 instances that are not on the screen


Forgot to answer this one.
For this you can just use the "is on screen" condition. I think that's the best way to shortlist.

Sprite is on screen
check distance

That way you first pick only the instances that are on screen, and then you can run your distance calculations on just those.
Follow my progress on Twitter
or in this thread Archer Devlog
B
44
S
20
G
19
Posts: 1,092
Reputation: 14,378

Post » Thu Sep 28, 2017 8:46 pm

Thanks a lot @tunepunk for the capx and the tips

I do use at the moment all the ones that you mentioned the (Line of sight, Is on screen, boolean is Active) etc... but the cpu still goes high when I'm checking distances just between 16 objects on the screen, the only one that I didn't try yet is like the test you did putting all 16 UID in a list and just keep checking distances from that list but I'm not sure if this is even possible to do, I been playing with your capx to see if I can make it work but no luck, I see there is a new feature in c3 that it looks interesting that I didn't know existed the one you use in your capx the plugin "Picked" I may this can help to put the picking in list and just loop through that list I will have to keep testing.

For my purpose, I need to be able to check distances every thick between the objects on screen and depends on what distances are then apply some actions to them so I need to refer to them one by one independently is quite complicated probably to make it work with a list

And I agree with you the best results I had from all the Tests that I did, the Line of sight was the winner all the time is very optimized
B
48
S
30
G
92
Posts: 363
Reputation: 51,384

Post » Thu Sep 28, 2017 9:02 pm

@tarek2

16 objects doesn't sound like a lot. Care to explain how it works?, maybe I can come up with something more efficient in your case.

Are they all checking distance too eachother and get picked if colliding?
Follow my progress on Twitter
or in this thread Archer Devlog
B
44
S
20
G
19
Posts: 1,092
Reputation: 14,378

Next

Return to Construct 2 General

Who is online

Users browsing this forum: No registered users and 14 guests