Instancing a thousand scene with a texture

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Gary_CHAN

I am now making a 2D game which need to show a small part of a texture. The mask is at random shapes so I try to use polygon2D to do the job in script by setting coordinates I am able to make the masks and only show the desired part. I make a scene of the polygon2D and instance them to the main scene.

The problem is that I need to make around a thousand of that scene at the same time and it crashes when I run it at the editor even if I reduced to 300 instances. It is ok to load the game for 300 instances if I export to window and run it. It is fast to load (around half a second) but it lags when I drag the polygon. It also crashes when I add 600 instances.

The texture is a PNG file of 256px * 256 px (161KB).
my instance scene is at follow structure:
|__ Control (for mouse capture)
|__ Polygon2D (which is the mask)
|__ Area2D (for detecting other pieces)
| |__ CollisionShape2D
|__ Area2D (for detecting other pieces)
| |__ CollisionShape2D
|__ Area2D (for detecting other pieces)
| |__ CollisionShape2D
|__ Area2D (for detecting other pieces)
| |__ CollisionShape2D

And my main scene is just a Control node.
It crashes even though I deleted all the Area2D nodes. So I wonder if it is because when I instance it 1000 times, the texture is loaded 1000 times so it stacks up very large and crashes? (the program in Windows Task Manager shows only 371MB when I once loaded 576 instances and it used less then 3 seconds )
if so, Is there any work-around?

It should not crash on that. 1000 polygons might be a lot depending on how many points they have. Godot is quite slow at drawing polygons at the moment so it would be laggy at worst, but still should run normally. Do you have a test project reproducing the issue?

Zylann | 2019-07-12 13:27

Thank you for replying.
By crashing I mean the project is not responsive and windows say no response. But the editor is fine so I can just press stop and press play to run another time. My computer is quite old but when I run the executable with instancing over 600, my computer didn’t lag but the executable become unresponsive.

Here are the test project :
MovingPuzzleTest.rar - Google Drive

In the first scene, slide the number of puzzle to over 600 and I don’t know if size matters or not. In the mean time, not all the puzzle will be shown in the screen but it is actually instanced.

Almost every time, when number is over 600. It will go unresponsive. Sometimes it loads correctly but when I try to move one of the puzzle, it will go unresponsive again.

Gary_CHAN | 2019-07-12 14:53

I profiled the draw_puzzle() function and here are my results for each choices from the main menu:

4 pieces: 0.002 seconds
16 pieces: 0.008 seconds
64 pieces: 0.044 seconds
121 pieces: 0.127 seconds
196 pieces: 0.312 seconds
256 pieces: 0.621 seconds
324 pieces: 1.2 seconds
400 pieces: 2.2 seconds
529 pieces: 4.6 seconds
625 pieces: 6.9 seconds
784 pieces: 12 seconds
961 pieces: 19 seconds

So it’s not really a bug, it’s just really slow to create all these things.
625 pieces creates 7136 instances, so yeah, this is way more than a thousand. I can imagine this being quite slow to create at once.
If you need such a high amount of objects, you should maybe show a progress bar because the game appears to run smoothly after that.
Otherwise, you may have to rethink the way you designed your system. Nodes are easy but that ease of use comes with a cost. For example, keep in mind a single Node2D without a script and doesn’t draw anything already weights around 250 bytes (derived nodes are heavier). You could stream them, use custom draw approaches, avoid using nodes etc.

Further notes:
With 961 pieces (which creates 19325 instances, each containing a dozen nodes) during node creation, memory goes up to 2.3 Gb, but goes down to 1 Gb afterwards. That means depending on the platform you run this game, it might crash for real due to being out of memory. Consider creating nodes progressively and display a loading bar, or change your strategy.

Zylann | 2019-07-12 18:21

Thank you so much. After reading the comment from you, I started to make a custom draw method(to draw pixels of the required area) and try to reduce as much node as I can. Now the puzzle piece is just a TextureRect, one Area2D and one CollisionShape2D and with 961 pieces, the game only takes 305 MB. Although it loads slowly (still about 20s), it runs smoothly even on my phone. Really thanks a lot. Now I start to use the profiler more often. It seems very powerful. And I didnt realise making an empty node will have such impact.

I dont know if it is stupid to ask( I am new to programming so sorry first). What do you mean by “stream”? Is it a godot function? And is there any standard procedure to creating nodes progressively?

Gary_CHAN | 2019-07-14 15:11

“Streaming” is a strategy, not a feature Godot has in particular. It means you would load only nodes you need right now (i.e those you can see + some margin), because nodes further away can wait to be loaded later since they can’t be seen anyways.
There are various ways to implement this, but in your case maybe it’s not needed after all.

Zylann | 2019-07-14 15:58

Oh I see. Thank you. I think I will try to add a progress bar and some animation while the game is loading

Gary_CHAN | 2019-07-14 16:48