I’m working on a small 2D mobile game and have started noticing performance drops when a lot of units are created and removed during gameplay.
At the moment I’m using instantiate() and queue_free() whenever an enemy or unit enters or leaves the scene. It works fine with a small number of objects, but larger battles are starting to produce occasional stutters.
I’ve been looking at how other strategy games handle large numbers of units, and Stick War: Legacy is a good example of a game where many characters can be active on screen at once. While researching it, I also came across discussions about Stick War Legacy Mod APK on stickwarmods, which got me thinking about how additional gameplay elements or larger battles could affect object creation, memory usage, and overall performance on mobile devices.
I’m considering switching to object pooling, but I’m not sure whether I’m optimizing too early. For those who have worked on Godot games with lots of short-lived objects, how do you decide when pooling is actually worthwhile? Do you usually profile first and look specifically at allocation/freeing costs, or is there a practical threshold where you’d recommend introducing a pool?
Pooling is pretty much standard practice and you should not think of it as anything special. However it is pointless pooling everything. So I pool things if I know the maximum number I will need (ie the min size of the pool), the objects are pretty much identical to each other, they are used often and their lifetimes are pretty short. Also if they are fairly complex objects. A simple scene is pointless to pool.
So a boss scene that appears once at the end of a level is not pooled. A rock scene that has no physics, area detections or animations I instantiate. An enemy that flies in from the left and disappears off to the right in waves, that is an ideal pooling candidate.
Instantiating scenes can be quite a heavy operation depending on what they contain. The engine often has quite a bit of work to do introducing them into the tree and physics systems etc. For non pooled items that are large and complex, like entire world chunks containing many sub scenes, I would use background loading with threads. This is a bit of a pain to do but makes an incredible difference.
Another thing I do even with pools is to only allow one instantiation per frame. So I generate a queue of required enemies and process it just once per frame. This can help immensely too.
But like you, during prototyping I instantiate and queue_free everything, however it is amazing how quickly it starts to be a problem. It is only then that I refactor to pool, background load or queue when it is obvious which scenes would benefit from which approach.
Hope that helps in some way.
PS If you are encountering stuttering already it is only going to get worse. As soon as it starts happening you need to start optimising to get rid of it. Adding a pool or a queue or a background loading system is not optimising too early. It is part of building the foundations. Make them as reusable components and you only have to make them once and you can reuse them in your future projects too.