Hi,

I just started switching my game to Godot yesterday, after running into some serious garbage collection issues that I couldn't figure out. It's a bit of an odd engine comparatively, but I'm liking it so far. (Especially the lack of GC to worry about.)

I have run into an issue optimizing the game, however. Right now I'm creating a triple ring of fifty bullets every ten frames, which drops the game down to ~40-35 fps. They're all Area2D nodes with a Sprite, a circle CollisionShape2D and a Tween (used on alpha and size on creation, and collision with the player). They all queue.free() when colliding with the player, or leaving the gameplay area.

A lot of the stuff that I read about on this topic spoke about pooling. I tried to implement a pooling system (I moved a bullet to 0,0 whenever it got destroyed, added it to an array, and then pulled from that array instead of instancing a new bullet scene) but it lagged more, and didn't seem to function correctly.

In my previous engine, I had to implement a lower level class which wasn't included in the base engine (an OpenFL Tilemap, for reference) for rendering, as well as do radius checks with math. I tried to use radius checks in Godot, but it didn't perform as well as Area2D collision.

Currently all my programming is in GDScript, which I've heard isn't the best...

Any help or ideas would be appreciated, thanks!

cant really give good advice without a sample project, but i'll give some surface level advice. don't instantiate 50 bullets at once, instantiate them beforehand but keep them deactivated. activate them when you need them. in other words make a pool/cache of bullets. use distance_to_squared then distance_to squared is less accurate but uses less cpu. * regarding gc, i cant really give advice since i don't think i've ever run into the same problem. are you sure its a gc issue?

maybe try writing a godot module in c++ if you are really sure about the lag being caused by the gc. not that hard, even my noob c++ skills can do it when i follow the docs.

Oh, the GC issue is nonexistant in Godot. My previous engine had the GC issue. :P

I wasn't aware of the distance_to functions, I was doing it all manually. Would that still be faster than using Area2D collision?

I'm also not sure how to go about setting up a pool/cache. It's spoken of a lot, I've found, but my previous engine did all that automatically.

Hi and welcome to the forum! (nice avatar too, btw)

The trick is to keep the bullets as simple as possible. Only use a Sprite. Do not have any collision or scripts attached to the bullet. Then in your main game loop, iterate over all the bullets, move their position, check if they are out of the screen bounds (and kill them), or check if they hit the player (using something like distance_to_squared as @Jatz suggests).

You also do not want to constantly be creating and destroying bullets, as this causes slowdown. Create like 500 or what your max amount is, make them off screen and don't update them. Then when you want to create a bullet, just pull it from the pool.

I made this example project for you. It shows the basics on how to create and use an object pool. I didn't program in the collision (besides killing them when they go off screen) but it should be enough to show how to get good performance. Cheers.

Also might not be a great idea to use Tween or any alpha on the bullets. This can cause slowdown as well.

One other thing, you don't want to be spawning things every 10 frames. Your logic should be framerate independent, otherwise people on faster or slower machines will get a different experience. You can use a Timer that ticks every second (or half second or whatever) that calls the function that spawns the bullets.

Oooh, that's a very nice headstart into this, thank you!

I was using tweens to make bullet creation pretty, though now that I think about it, I could probably manually adjust the settings I want based on the bullets state from the previous frame to save a fair amount of power, correct?

I was also looking at that sample you posted: it looks like it instances bullets if there are none left in the pool. Am I seeing that correct, or should I pool more than I'll need to be safe?

Oops, I skimmed through the code too quickly: bullets are not instanced if none are left in the pool. I did a bit and set that up myself though.

Thanks again!

If you need more bullets, just set the original init_bullets to the max amount you would ever need (like 1000 instead of 500). You don't want to instance new bullets, as this defeats the purpose of the pool.

That's a fair point.

I've found another slight problem in having multiple types of bullets: loading a texture for each bullet drops the framerate a fair amount. Is there any better way to load textures for sprites? Perhaps simply changing the colour in code would be faster, though I couldn't get the colour to change without also effecting the white on my bullet sprite...

You can try making the bullet a Node2D, and then have several Sprites as children, each with their own texture, which you can show or hide depending on the type of bullet. That should work, but I don't know about performance.

If there's only going to be 1000 bullets then area2d and should be enough

2 months later
  • [deleted]

  • Edited

Hi.

From the accepted answer:

I made this example project for you...

Where can I download it?

@Tween - Welcome! My guess is that the example project got lost when this topic was recovered from the database incident. @cybereality - do you still have the project by any chance?

  • [deleted]

@TwistedTwigleg - Thanks! :)

9 days later
  • [deleted]

@cybereality - Thanks a lot!

a year later
7 months later